Pin change interrupt not firing with MySensors
-
@DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?
The only funny thing I see is at
2549 !MCO:SND:NODE NOT REGthis is because you set a 100ms timeout here:
#define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be madeset it to 0 or increase to e.g. 10000...
@tekka said in Pin change interrupt not firing with MySensors:
@DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?
That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level. For completeness I tried, but the outcome is the same; node wakes up immediately.
The only funny thing I see is at
2549 !MCO:SND:NODE NOT REGthis is because you set a 100ms timeout here:
#define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be madeset it to 0 or increase to e.g. 10000...
You're right! My bad. I'll change that to 2700, that's the approximate time the node needs to start up.
-
@tekka said in Pin change interrupt not firing with MySensors:
@DavidZH IRQ triggers only on LOW level when sleeping (see at328 datasheet) - what happens if you substitute all enableInterrupt(xyz, CHANGE) to enableInterrupt(xyz, LOW)?
That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level. For completeness I tried, but the outcome is the same; node wakes up immediately.
The only funny thing I see is at
2549 !MCO:SND:NODE NOT REGthis is because you set a 100ms timeout here:
#define MY_TRANSPORT_WAIT_READY_MS 100 //Start the node even if no connection to the GW could be madeset it to 0 or increase to e.g. 10000...
You're right! My bad. I'll change that to 2700, that's the approximate time the node needs to start up.
That is not true! Chapter 13, page 70, second part, first line: The External Interrupts can be triggered by a falling or rising edge or a low level.
For sleeping MCUs, you may have missed this here:
http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdfChapter 10.1 Sleep Modes (pg 39) => read note 3
If the node still wakes up, it could be triggered by the radio - this is something we need to investigate further. If you disable all IRQs (on ChanA-D) - does it still wake up?
-
I respectfully disagree: That states only INT_0 and INT_1, I am using PCI. Different mechanism and vectors.
About the radio waking it up: you mean interference? Or the interrupt? I think those are not the case, as he wake reason states -1, by timer. And if I flash the exact same sketch using the 2.0 library, the node stays asleep properly and wakes with the press of a button.
The thing I ran into when developing this node was that I could use PCI when using deep sleep, but when I wanted to add a timer to send a sensor value periodically as well, the node would only wake up with the timer, and only then register the interrupt events. -
I respectfully disagree: That states only INT_0 and INT_1, I am using PCI. Different mechanism and vectors.
About the radio waking it up: you mean interference? Or the interrupt? I think those are not the case, as he wake reason states -1, by timer. And if I flash the exact same sketch using the 2.0 library, the node stays asleep properly and wakes with the press of a button.
The thing I ran into when developing this node was that I could use PCI when using deep sleep, but when I wanted to add a timer to send a sensor value periodically as well, the node would only wake up with the timer, and only then register the interrupt events. -
No worries man! We're all learning as we're moving along with this project. And there's so much info in most of the posts that some parts will be missed. Inevitably.
-
Hi @Yveaux,
I have stripped it to one button on a RC-net and one led to see what I am doing, without changing the basic flow of the sketch. Also the node has been stripped bare. I have used a DIP version with the same bootloader (8MHz internal, 1V8 BOD by GertSanders, 3V3 power source) and the outcome is exactly the same:
- directly waking with 2.1.1, sleeping with 2.0.0.
- In both tests, all button presses are registered without problems.
- button library has nothing to do with it. When I use a simple
digitalRead(), all remains the same. - when I comment out the library call for the Interrupt (line 48), nothing changes.
/***************************************************************************/ // MySensors definitions #define MY_DEBUG #define MY_CORE_ONLY #define MY_BAUD_RATE 57600 // Lower as max because of 8 MHz Arduino #define EI_NOTEXTERNAL // Options for the EnableInterrupt library #define EI_NOTPORTB // to save flash space #define EI_NOTPORTD #define EI_ARDUINO_INTERRUPTED_PIN /**************************************************************************/ #include <Button.h> #include <EnableInterrupt.h> #include <MySensors.h> #define buttonPin 14 //A0 #define ledPin 8 #define PULLUP true #define INVERT true #define bounceTime 20 // A debounce time of 20 milliseconds usually works well for tactile button switches. #define sleepWait 1000 // Time to wait in ms before node sleeps (to be able to receive notification messages). volatile uint8_t interruptCount = 0; volatile bool buttonChanged; volatile bool buttonState; long lastButton; Button BtnA(buttonPin, PULLUP, INVERT, bounceTime); /**************************************************************************/ void presentation(void) { } /**************************************************************************/ void setup(void) { Serial.begin(57600); Serial.println("\nStarting test"); enableInterrupt(buttonPin, interrupted, CHANGE); pinMode(ledPin, OUTPUT); //pinMode(buttonPin, INPUT_PULLUP); //uncomment when testing without Button library lastButton = millis(); } /**************************************************************************/ void loop(void) { if (buttonChanged) { if (buttonState) { Serial.print("\nButton has changed "); Serial.print(interruptCount); Serial.println(" times."); digitalWrite(ledPin, HIGH); } else { Serial.println("\nButton is released."); digitalWrite(ledPin,LOW); } lastButton = millis(); buttonChanged = false; } if (!buttonChanged) { if (millis() > (lastButton + sleepWait)) { sleepNode(); } } } /**************************************************************************/ void interrupted() { interruptCount++; buttonChanged = true; //buttonState = !digitalRead(buttonPin); buttonState = BtnA.read(); } /**************************************************************************/ void sleepNode() { Serial.println("\nSleep..."); wait(30); sleep(0xff, 0x00, 0xff, 0x00, 0); wait(30); }Two other things caught my attention:
- In MY_CORE_ONLY there's no
serial.begin(), makes one wait awfully long for debug output... - When the node is in PWR_DOWN, my (Chinesium) USB-serial converter is unable to wake the node to upload new code. I have to keep the node awake with the button, and if that fails, shoot the bootloader again. I know the DTS-pin is functional, as the node resets when I start a serial window.
-
Hi @Yveaux,
I have stripped it to one button on a RC-net and one led to see what I am doing, without changing the basic flow of the sketch. Also the node has been stripped bare. I have used a DIP version with the same bootloader (8MHz internal, 1V8 BOD by GertSanders, 3V3 power source) and the outcome is exactly the same:
- directly waking with 2.1.1, sleeping with 2.0.0.
- In both tests, all button presses are registered without problems.
- button library has nothing to do with it. When I use a simple
digitalRead(), all remains the same. - when I comment out the library call for the Interrupt (line 48), nothing changes.
/***************************************************************************/ // MySensors definitions #define MY_DEBUG #define MY_CORE_ONLY #define MY_BAUD_RATE 57600 // Lower as max because of 8 MHz Arduino #define EI_NOTEXTERNAL // Options for the EnableInterrupt library #define EI_NOTPORTB // to save flash space #define EI_NOTPORTD #define EI_ARDUINO_INTERRUPTED_PIN /**************************************************************************/ #include <Button.h> #include <EnableInterrupt.h> #include <MySensors.h> #define buttonPin 14 //A0 #define ledPin 8 #define PULLUP true #define INVERT true #define bounceTime 20 // A debounce time of 20 milliseconds usually works well for tactile button switches. #define sleepWait 1000 // Time to wait in ms before node sleeps (to be able to receive notification messages). volatile uint8_t interruptCount = 0; volatile bool buttonChanged; volatile bool buttonState; long lastButton; Button BtnA(buttonPin, PULLUP, INVERT, bounceTime); /**************************************************************************/ void presentation(void) { } /**************************************************************************/ void setup(void) { Serial.begin(57600); Serial.println("\nStarting test"); enableInterrupt(buttonPin, interrupted, CHANGE); pinMode(ledPin, OUTPUT); //pinMode(buttonPin, INPUT_PULLUP); //uncomment when testing without Button library lastButton = millis(); } /**************************************************************************/ void loop(void) { if (buttonChanged) { if (buttonState) { Serial.print("\nButton has changed "); Serial.print(interruptCount); Serial.println(" times."); digitalWrite(ledPin, HIGH); } else { Serial.println("\nButton is released."); digitalWrite(ledPin,LOW); } lastButton = millis(); buttonChanged = false; } if (!buttonChanged) { if (millis() > (lastButton + sleepWait)) { sleepNode(); } } } /**************************************************************************/ void interrupted() { interruptCount++; buttonChanged = true; //buttonState = !digitalRead(buttonPin); buttonState = BtnA.read(); } /**************************************************************************/ void sleepNode() { Serial.println("\nSleep..."); wait(30); sleep(0xff, 0x00, 0xff, 0x00, 0); wait(30); }Two other things caught my attention:
- In MY_CORE_ONLY there's no
serial.begin(), makes one wait awfully long for debug output... - When the node is in PWR_DOWN, my (Chinesium) USB-serial converter is unable to wake the node to upload new code. I have to keep the node awake with the button, and if that fails, shoot the bootloader again. I know the DTS-pin is functional, as the node resets when I start a serial window.
@DavidZH The issue is caused because the way you use the sleep() function.
You 'abuse' the sleep() implementation that takes 2 interrupts (this prototype) to be able to sleep 'forever' (timeout 0).
However, by passing two invalid interrupt numbers, the MySensors stack translates this into a regular sleep() (this prototype) for which a timeout value of 0 means to return immediately.In the core, calling either sleep(0xff, 0x00, 0xff, 0x00, 0) or sleep(0) will lead to the same call to the hwSleep() implementation, which will return immediately.
As a quick test, could you try replacing the code starting here:
if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) { // both IRQs result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS); } else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { // one IRQ result = hwSleep(interrupt1, mode1, sleepingTimeMS); } else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { // no IRQ result = hwSleep(sleepingTimeMS); }by
result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS);and see if that solves your issue?
-
It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.
Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.
- When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.
I do see use cases for this: like an alarm-base station. With multiple inputs for the various detector loops. When the power fails (either by accident or intentionally) the base should go in low power mode to save the battery. And send a periodical heartbeat.
Or a scene controller in an inaccessible spot with a sensor attached.edit: I've been browsing around MyHwAVR.cpp for a while, but my coding is not at that high of a level at this moment, that I can provide any useful input.
-
It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.
Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.
- When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.
I do see use cases for this: like an alarm-base station. With multiple inputs for the various detector loops. When the power fails (either by accident or intentionally) the base should go in low power mode to save the battery. And send a periodical heartbeat.
Or a scene controller in an inaccessible spot with a sensor attached.edit: I've been browsing around MyHwAVR.cpp for a while, but my coding is not at that high of a level at this moment, that I can provide any useful input.
@DavidZH said in Pin change interrupt not firing with MySensors:
It did! Thanks a bunch! I had a feeling it was to be found in that part of the code.
Great!
Strange thing is: it still returns -1 as wake up reason. And that brings me back to my original problem.
Well, that function is setup to either return the interrupt number, or -1 if it didn't wake from interrupt.
You woke it differently, hence the return code of -1, see here.- When I want to add a timed sensor by setting a time as last argument, the node will not wake up when an interrupt takes place. It does register the interrupt, as the counter increases with every press. But it will only wake when the timer expires and only then display the updated counter.
The actual sleep method differs whether a timeout is passed or not, see here.
I would have to consult the datasheet and dive into the different sleeping methods, but that probably is the reason of not waking up.Again, you are using the library in an undocumented/untested way, so, unless you're able to read/modify the code yourself, I advise you to stick to the suggested use cases.