[Solved] Solid green/lockup after ~44 minutes

I think this is a higher level question regarding resources rather than a code error, so I’ll hold off posting the code (which is a mess in transition right now) unless necessary.

Rather simple code, set pin to output and drive low, set TIM3 for 2ms, and delay(1000). The timer interrupt changes the pin back to input. After the delay I Serial.print() a short message. This is all in loop().

After about 44 minutes (I count the lines in the log, two runs were off by one second), the light is solid green, and the output is stuck low, so the timer has not yet fired.

The second run I was nearby, and noticed that a short time before the light went solid green, it was blinking a fast green, and the serial output was printing only about every six(?) seconds. I think the flashing may have been faster than the “Looking for internet” flash, but am not sure.

I suppose this could be a flaw in my C++ conversion, but am wondering if there is anything magical about 44 minutes and internet connectivity, assuming that is what the flashing green indicates. Am I clobbering something by using TIM3? The interrupt is only changing the pin to input and saving micros() in a volatile. I am setting NVIC_IRQChannelPreemptionPriority to 14 and NVIC_IRQChannelSubPriority to 1.

Edit:
I ran again in MANUAL mode, and it again froze with a solid white light, after about 46.5 minutes. I’m going to see how far I have to strip this down before the problem goes away.

Well, that was nothing like what I was expecting.

It seems calling into a C++ method from an ISR is a no-no. I am assuming something goes wrong on the call stack with myInstance->myISR(), and I am crashing the stack after a fixed number of interrupts. I can crank my timers up and down, and get the lockup after about the same number of calls.

Calling a class method from within an ISR is not inherently dangerous. However, what you do in that method certainly can be. I have been making such calls for the better part of three decades so I know it works.

Make sure your object is global in scope with a lifetime that covers the runtime of the ISR. Test the value of the object pointer in the ISR before calling it to ensure it is not NULL.

Inside your method, make sure you keep it as short and fast as possible, and don’t make any system calls unless you are certain that it is safe and reentrant. It is always best to do as little as possible in the ISR and leave the heavy lifting for the main program.

I hope this helps.

1 Like

Good to know. I thought I had this all figured out, but in reducing the code, I went too far. It was not the removal of the C++ call that fixed it, but a mistake I made removing a reference to a member. So the "working" case was only actually starting my timer the first time around. I think. I believe there are two changes I thought made a difference, but may have misinterpreted the outcome. I need to backtrack.

I know I didn't have NULL, I have a state enum I am checking at each step, and that always seem to be in the correct state. But I will watch for that. I have saved the this pointer in a static field of the class, is that a proper scope?

It is pretty short and sweet. I am using low level calls to stop the timer and change an IO pin, then update my state enum and grab a micros() value to log from the main loop. I had the algorithm working as a test in C, decided I would clean it up and make a class before I moved on.

Thanks for the tips.

Looks like this was a memory leak in attachSystemInterrupt.