[SOLVED] Pinchangeint freeze the arduino

I am working with an arduino mega 2560 with many different meteorological sensors connected to it.

Since i need many external interrupts (more than those provided by mega2560), i use PinchangeInt library, what works well, at least for the examples of the library.

I added the library to my code, and it seems to works well, but if i disconnect the arduino from my laptop, when i connect it again, the code freeze in the interrupts declaration by pinchangeint library. I added many serial.print lines to check where the code freeze, until to discover it occurs when declaring the interrupts.

If this is not rare enough, if i upload EXACTLY the same code, the code works well and the interrupts also works. If i unpplug it from the laptop, the code freeze again exactly in the same time.

I spent one week changing things in the code, changing the position of the interrupts declarations, adding serial.print lines, testing again and again the library examples… but nothing changes… and this does not happend when i run the examples of the library.

I attatch the complete code (it is so long for paste here directly).

Do you know why this happend? Did you know if there is any incompatibility between the libraries i use what could produce this behavior? What am i doing wrong?

Thanks so much!

Ardudrop_2_v0005.ino (15.5 KB)

I added many serial.print lines to check where the code freeze, until to discover it occurs when declaring the interrupts.

Print statements1 in interrupts take extra time causing the freeze to get worse.

you should try to minimize the code (e.g. use smallest datatype, fastest math) in the interrupts so they are handled as fast as possible and before the next one comes in.

1 disclaimer - did not look at the actual code

Thanks for your comment.

I mean i wrote serial print functions before and after to declare the interrupts, not inside the function called during the interrupt. I know that serial print and delays inside the interrupt function could result in rare behaviours.

Anyway, i added the print function in order to discover where was the problem, but the coded freezed already before i added those function. To have as fast as possible interrupts, Inside the interrupt functions i only disabble the corresponding interrupt pin and change the state of one boolean variable, what are used during the loop to decide what to do/measure.

a look at the code, some comments to improve the code… (point 10 is most important)
(your coding style is quite good by the way)

  1. a lot of delay() statements that are blocking and disallow the processor do anything meaningful (except interrupts)
    e.g. in
  2. a lot of print statements that can be faster
    e.g.
    Serial.print("/"); // this uses a for loop under the hood until end of string is found
    ==>
    Serial.print(’/’); // is faster
    Serial.write(’/’); // even more faster as it knows it only writes one char.

Serial.print("; "); // only if the space is really needed use it, otherwise use ‘;’ like above.
You can use the ‘\t’ [TAB] character as separator which is both pleasant for humans and Excel

  1. long ReadInnerVcc() {
    returns a long but it never does return anything. NOt used either => should be
    void ReadInnerVcc() {

  2. The calculation of InnerVcc can be simplified
    InnerVcc is a float and you can merge all math in one expression that the compiler optimizes compile time.

5 void ReadTempHum(){
DHT.read21(DHT21Pin); // chk is not used so do not declare it as volatile
Temperature = DHT.temperature;
Humidity = DHT.humidity;
}

long startTime = millis();
should be
unsigned long startTime = millis();

while(millis() < startTime + period) { }
should be
while(millis() - startTime < period) { } // overflow save, period should be unsigned long too BTW

unsigned int counter = 0; // B/W counter for sensor
should be volatile as it is used inside an interrupt.

volatile unsigned int RPM = ((counter/2)60)/(period/1000);
as period = 10000 this formula can be optimized to
unsigned int RPM = counter
3;

// Sleep and power down arduino board
void sleepNow(){
sleep_enable(); // enables the sleep bit in the mcucr register
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
PCintPort::attachInterrupt(RTCAlarmPin, RTCAlarm, CHANGE);
PCintPort::attachInterrupt(TestButtonPin, TestState, RISING);
PCintPort::attachInterrupt(IrrigationButtonPin, IrrigationState, RISING);
sleep_mode(); // Arduino board goes to sleep
sleep_cpu();
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // Disable sleep…
PCintPort::detachInterrupt(RTCAlarmPin);
PCintPort::detachInterrupt(TestButtonPin);
PCintPort::detachInterrupt(IrrigationButtonPin);
}
it is often better to deattach the interrupts in the reverse order.
Is this power save mode really needed as all sensors probably still use a lot more…

  1. optimized.
    void CheckDevice(){
    ReadBattery();
    if (Battery >= 12.70) setColor(0, 255, 255); //Cyan
    else if (Battery >= 12.50) setColor(0, 80 ,239);
    else if (Battery >= 12.42) setColor(0, 0, 255); //Blue
    else if (Battery >= 12.32) setColor(0, 138, 0);
    else if (Battery >= 12.20) setColor(0, 255, 0); //Green
    else if (Battery >= 12.06) setColor(255, 255, 255); //White
    else if (Battery >= 11.90) setColor(255, 255, 0); //Yellow
    else if (Battery >= 11.75) setColor(255, 127, 0);
    else if (Battery >= 11.58) setColor(244, 114, 208);
    else if (Battery >= 11.31) setColor(143, 0, 255);
    else if (Battery >= 10.50) setColor(75, 0, 130);
    else setColor(255, 0, 0); //Red
    delay(1000);
    setColor(0, 0, 0);
    }

@robtillaart,

THANKS SO MUCH for all your comments!! I really apprecite them! I will made the necessary changes to improve the code.

After expend all the night working on this,i have it running.

I don´t know why, but the problem seems to be related to the sleep function and where the interrupts are declared and cancelled.

My “solution” consisted on to move the interrupt cancelation to each interrupt function, and to move the interrupts declaration to the main program outside the sleepNow() function. Adding a delay after the wake up of the board was also fundamental. I used 300 ms, because smaller values does not solve the issue or produce rare behaviour at the interrupts by pushbuttons.

After many try-error modifications along all the night, the code is not working, at least for the moment, and without test other interrupts except those triggered by 2 pushbuttons. I don’t say that this is the solution to the problem, but the modification what made my code works. I attach here the new version of the code just in case you want to compare with the old one.

Anyway, it is important to say that this code is not finished… so, be adviced that there are different sections of the code what are incomplete, other could be improved, other seems not to have so much sense,… but this is because i am still working on it.

@robtillaart: i added some of the modifications you propose, but other are still required. I was ocussed onsolve the issue. Now, i could work on improve the code following your recomendations. Thanks so much!

Ardudrop_2_v0006.ino (15.4 KB)

BTW,

During the long nigth i also tested other solutions, such as to use the library… what allow to send the arduino to sleep and use different options to wake it up, such as use an sleep period or an external interrupt. However, it seems that, it could onbe be used for normal interrupts, not to pinchangein interrupts… At least during the tests i made. Maybe it couldbe interesting to explore this option in the future.