Gateway MoteinoMEGA freezes after 20 mins [SOLVED]

Started by K1JOS, September 01, 2014, 09:29:52 PM

Felix

Good conversation going here and I don't think I have anything to add. Charly's suggestion seems legit.

K1JOS

OK thanks to everyone --  great advice and gives me lots to check out tonight.  Right now I am running everyhting after taking Felix's advice to place a 10K on the INT pin to Vcc and I placed a 0.01uF on the INT pin to ground.  Waiting to see if it locks up.  If so then onto the INT changes your recommend.

Is there a way to disable only a specific interrupt or is it All or Nothing? 

I defer to Felix but do I have to be concerned what may happen to the RFM69 module as the radio uses a Moteino interrupt.  Will shutting off all interrupts possible corrupt data packets that may be in the middle of transfer between the RF69 module and the ATMega??

Charly86

#17
KIJOS,

of course you can disable only the interrupt you're using, it's my favorite way also  ;)
in your case INT1

  bitClear(EIMSK, INT1); // instead of cli();
  ....
  bitSet(EIMSK, INT1); // instead of sei();


disabling interrupt do not forget the IRQ, it's just delay the time when it will be treated.

By the way I think's it's not a problem for 2 reasons :
1st : code is very fast between cli/sei
2nd : RFM69 fire interrupt when a packet available, so even if you get it some ms later, it should be fine (until another one arrive so fast you did not had time to catch the 1st) but in this case CRC is you friend, frame could be missed but not seen as a valid (I think)


K1JOS

Charly86,

Can I turn off interrupts at the top of the loop before I do the digitalRead of the pins and then re-enable the interrupt as the last step in the Loop??

Quote from: Charly86 on September 02, 2014, 05:07:51 PM
K1JOS

I recommend you to disable the interrupt when using var that can be modified in isr AND in the loop

in loop the line
last_micros = 0;
is one line, but generated assembler code will be more because it's long var, 4 bytes to reset. So if interrupt is fired in the middle you'll have "unknown state" of your var and unpredictable results.

Interrupt are so powerfull  ;D, but attention need to be at the same level to deal with them  ;)

Would you mind test this way just to see ?

void Loop(){
// just a reading bit no problem on this one test
if (interrupt_flag){    
    button1 = !digitalRead(18);  
    button2 = !digitalRead(19);
    button3 = !digitalRead(20);
    button4 = !digitalRead(21);
    ProcessButtons();  // this does all the work
    cli();
    interrupt_flag = false;  //reset for next interrupt 
    last_micros = 0; // must reset for next interrupt to prevent overflow
    sei();
 } 
}


Charly86

K1JOS,

I'm not sure to understand, without a schematic to have a global overview, If I understand each button is connected to a port and also grouped to go to the interrupt line INT1 that's it ?

If so, may be it can be easier to use the PIN change Interrupt on all 4 buttons where they are connected, this will give you 4 independent interrupt (one for each button) and no need to use and group INT1 with diodes. The trick is that you do not need any hardware change, and deboucing can be done individually for each button  ;)

Just an idea

K1JOS

Hi Charly,

I got this advice originally on the Arduino forum to stick with hardware interrupt for several reasons listed on the Arduino page (see quotes below):

Quote
This library was designed for the Arduino Uno/Duemilanove, and has been reported to work fine on the Nano, but it has not been tested there. As mentioned above, MEGA support is included but support for that platform is weak.

Since the MegaMoteino is a different ATMega than the MEGA AtmEGA 328 Arduino I was more concerned

Quote
Furthermore, the pin change interrupts are grouped into 3 "port"s on the MCU, so there are only 3 interrupt vectors (subroutines) for the entire body of 20 pins. This makes the job of resolving the action on a single interrupt even more complicated. The interrupt routine should be fast, but complication is the enemy of speed

So I thought the using the single hardware INT (all 4 'button' pins are pulled-up and tied to INT pin so that when the button is shorted to ground, the other buttons remain high and only the presed button is read low.  It seemed clean and straight forward with little code overhead.

Jerry

Charly86

Jerry,

you're right, I forgot this point, one ISR per port, so one ISR for 8 bits ;-)

Mega works same way as 328, more functions, more port, but very similar, the deal is that it's not standard for Arduino and thus no classic files exists for pin definition and even on library, so each one can have it's own pin definitions (the new ones ont 1284) that make some headaches. Felix choosed the mighty1284p format which seems to be a good one, but unfortunatly on Arduino IDE 1.5.x the pins definitions are not the same even for IRQ. Arduino is just a nice "presentation" and simplifies things and have so much libraries !!!!!!!
But behind the scene it's just a microcontroller as other, so as you're confortable with IRQ on them, whatever the target you will use, it will work the same. I did not had a change to test on multiple port pin change IRQ because until now I did not need it, but it's really worth it to be able to do so  ;)
But you're choice will work fine also ;-)

K1JOS

Well I used the following in my Loop:

void loop() {
  // LOOP STEP 1 Button interrupt and debounce
  if (interrupt_flag){    
    bitClear(EIMSK, INT0);  // turn off INT0
    button1 = !digitalRead(M_CW_BUTTON);  
    button2 = !digitalRead(M_OFF_BUTTON);
    button3 = !digitalRead(RESET_BUT);
    button4 = !digitalRead(M_CCW_BUTTON);
    ProcessButtons();
    interrupt_flag = false;  //reset for next interrupt  //@  do i need some delay first to finisjh digital Read?
    last_micros = 0; // must reset for next interrupt
    bitSet(EIMSK, INT0);  // turn on INT0
  }


And it still freezes after 20 min while the rest of the subroutines chug away correctly.  Next I will swap Mega's.

Charly86

If I remember correctly you're attached to INT1 not INT0 you need to change in bitset and bitclear according to INT1
But at first I suggest cli sei to be sure at first.

K1JOS

I wanted to make sure it wasnt a bad "pin" so I changed my interrupt pin from INT1 (pin 11) to INT0 (pin10) and just kept it that way.  Sorry for the confusion.  OK I will try cli and sei now.

Charly86

ah ok, sorry, that makes sense now with your explanations ;)

K1JOS

Well, good news is its not the MegaMoteinos as swapping them made no difference.  So i8ts the code.

I placed the cli() and sei() instead of the bitClear(EIMSK, INT0) and something strange happened. Two of the buttons worked for more than an hour but as soon as I hit the first button the wholoe Mega stopped cold... including the LCD updating and LED blinking.  I think this gives me a clue that its something in the code that processes some of the buttons actions and not others.  It is still weird that with no button press nothing is going on except radio receive and LCD updating but I now can focus in more.  Has to wait until later today, work comes first :-)

Felix

You know, watching this conversation it reminds me of learning how to use interrupts the hard way. And in fact I don't know if there's an easy way. After so many hours/days of pulling hairs you develop that 6th sense of how these things work. You will still make mistakes, but the more you code the better you get at it, and fewer mistakes.

Charly86

+1 Felix,

IRQ are ..... need to be mastered, what I've learned with them is when using them and have a problem major pb is coming from IRQ.

What you can do is to try to isolate the pb, just HW with your buttons, diodes and IRQ and just code to deal with the button and the IRQ. You seem to have a display and other things, so we're not even sure it's coming from IRQ (more if you use other people library)
You have no idea of # of lib I trusted before seeing that bugs where not in my code but on the libs !!!

K1JOS

Using cli() and sei() as Charly suggested, the freeze occurs in Button Processing subroutine where only one of the four button calls my LCD update subroutine directly from this subroutine rather than the usual call from my Loop().  Now this LCD subroutine is called liberally and its weird that before introducing cli and sei the freeze would not affect LCD updating.  None of my subroutines is passing any variables and I have all flags and variable as 'volatile' now.
Well I'm digging in to further isolate and will report back.  I think your right, debuggin is an important part of getting more proficient with coding.