Hello everyone, has anyone used the FastAccelStepper motor library before? I've been using this library for some project testing, but I've found that it conflicts with external interrupts. Let me briefly explain the situation. I'm using PIN2 and PIN3 as limit switches for two directions, implemented as external interrupts. When my ISR (Interrupt Service Routine) is triggered, it means the switch is closed. Buttons 18 and 19 control the movement in these two directions; as long as I keep one of them pressed, the motor keeps moving, and it stops when I release the button. Ideally, when an ISR is triggered, the motor should also be forcibly stopped, which is the expected and correct
behavior.
However, in reality, when the ISR is occasionally triggered, the motor sometimes continues to move uncontrollably forward and doesn't stop even when released. This happens at a frequency of about 1/80. It seems like a conflict between the external interrupt and the library, and I've ruled out any issues with my hardware. Inside my external ISR, I have the statement stepper->forceStopAndNewPosition(0);. The author of the library clearly states that this statement can be used within an interrupt, with the original sentence being: " // abruptly stop the running stepper without deceleration.
// This can be called from an interrupt !."
If your code is written correctly, there is no need to use interrupts with the limit switches. Use other pins instead, and digitalRead() to read them, (or direct port access, which is actually faster than an interrupt) and creates many fewer problems with other code.
Hello, it's nice to see you again. Last time I also asked some questions, and you gave me a lot of help. Thank you very much. To get back to the point, using ISR in some emergency situations is a safe way, and this is just a simplified situation for me. Do you think polling is faster and more effective in handling urgent matters than ISR? I don't quite think so. But I think your situation may occur when the code volume is very small.
I do, as do lots of folks on the forum. Your MCU can do 1000s of things per second which is plenty fast enough to detect a limit switch and stop movement given a properly designed sketch that doesn't have any blocking code. As @jim-p points out, you also didn't declare your variable volatile and you didn't make local copies when using them in your main code - both issues that go away when you forget about ISRs and just poll the limit switches each time through loop.
Yes. This instruction to read digital pin 2 on an Uno R3 takes 1 machine cycle, or 62.5 nanoseconds.
byte pin_value = PIND&(1<<2);
And, as pointed out by @blh64, with the typical mistake of forgetting to set the shared variable volatile, there is no guarantee that main program will see the value changed by the ISR. This is hardly a good idea for an emergency stop or limit switch.
Thank you very much for your reply. I just saw your suggestion and I think it is very useful. I am currently making code changes and will conduct testing after the changes are completed. I will inform you of the test results. Thank you again
Thank you very much. I will follow your advice and add volatile before my variables. In fact, I did use a non ISR version to implement the content of this code in a loop manner, which can indeed solve the problem as you said. However, I am simulating an emergency situation, and I think you are right. It is indeed fast enough in a loop, but I think ISR is very necessary in very urgent situations. What do you think?
@jim-p@blh64@jremington
After following your advice, I added the keyword 'volatile', but the error still occurs with a probability of around 1/80. However, I am still very grateful to you, and adding this keyword is very necessary. At present, it seems that this issue is a conflict between ISR and the motor library. The external interrupt priority of Mega 2560 is very high, and this library uses timer interrupts. However, the author also proposed “stepper ->forceStopAndNewPosition (0); ” It can be used in ISR, otherwise I wouldn't have used it this way. This statement is for emergency stop, and I have tried to make the ISR statement as short as possible
Still not convinced. What a human may perceive as "urgent" can be thought of as painfully slow in terms of an MCU. We operate on different time scales. Do you think your car does most of its work with ISR since you are travelling down the road at a potentially lethal speed? [hint: it does not. the CAN bus sends messages all around the vehicle and certain, dedicated controllers do take care of critical tasks, but also participate on the CAN bus and other things].
If your application is more "urgent" than that, then maybe you need an ISR, but I am still not convinced.
Thank you very much for your reply. What you said is very reasonable. But in some special cases, such as when my teacher or client requires me to use ISR to achieve my situation, that's another situation. I have to use ISR to simulate this very urgent situation. What do you think is the problem with my code? Is it a conflict between my external interrupt and the motor library?
HI, @arduinoer_cc
Have you tried to use polling method, before trying ISR?
If not, then it might be worth a try.
What is your overall project and if the ISR are for Emergency Stop then that is not the way to do it.
The end stops should not be connected to ANY software application, get the endstops to keep a relay ON to supply motor current, an endstop tripped will cause the relay to turn off the motor current.
That is a completely different reason. Something you should have mentioned a few posts ago
So now we are required to use an ISR and make it work.
First off, the variables you use in the ISR and the main program must be declared as volatile so the compiler does not optimize their access incorrectly.
Second, for an 8 bit MCU (which board are you using?), you can not simply access those volatile variables that are larger than 8 bits in the main program since that access can not be done atomically. You will need to turn off interrupts, make a local copy, turn interrupts back on, and then proceed to use the copy. If you do not, there is a chance that the variable will be corrupted.
Apply those learnings to your code. Test it out. Report back with both the new code and the results and we can proceed.
hi, Thank you very much for your reply. I have tried using polling to implement it in my other version, and it was not a problem. There were no bugs like using ISR But my current situation is that I have to use ISR to complete it. But thank you very much for your advice.
Thank you again for your reply. I added volatile before my variable, but the error still occurred. I am using mega 2560. As for the second point you mentioned, I will try it now and let you know the result later