Using Hardware Serial with Interrupt

A robot cart (MCU=Mega2560) receives commands from a remote controller (NanoR3) using HC-12 comms. However, emergency commands must be received using a Serial.available() polling scenario. Thus, the Mega frequently misses the 'stop' CMD because it is busy running PID loops for the motors, getting IMU Yaw data or GNSS Data. As the Serial Ports on the Mega are hardware based and the Rx, Tx pins are interrupt capable, it seems that an interrupt service routine should be possible. However, all the Google searches and not found example code that I could implement.

Essentially the plan: Upon receiving a byte on serial comms, trigger a call to an ISR which can then determine if an emergency exists.

Serial polling will not permit time critical commands from the Remote Controller. Any Ideas any one?

The serial port is already under interrupt control in the Arduino core framework.

It takes only a microsecond or so to call Serial.available() and check whether characters have been received (via the serial receive ISR) and are in the buffer, so feel free to add that to any of your PID loops, or other code.

Fetch and process the characters whenever it seems convenient or expedient, as that is also very fast. The ^C (CTRL-C) character is often used as an emergency stop or pause flag.

I once faced similar demands for a satellite receiver up in a billion GBP satellite, handling emergency with the highest priority.
Could You post the code for suggestions?
Checking for emergency out around in the code might be a solution.

Thanks quick reply. Yes, I know that hardware serial is interrupt driven but I couldn't find how much latency would be added nor if Serial.available() is 'latched' for later checking nor that it could function essentially as the ISR. I am currently doing this check after many PID loops each 25msec long. I think you are saying that I should not worry because the latency is essentially negligible. If so, good news.

I may use a while (!Serial.available()) {} approach where the PID loop (using millis() approach) is inside the while (). Do you think this is reasonable?

I have seen your posts on the 9 DoF magnetic calibration and I am very impressed with the info and your help. So, I have a question regarding 'return' whick I will ask here because it relates to the above issue, i.e. once the Emergency CMD is determined (Serial.available() processed). The Serial Comms code is inside the PID function which is inside a switch/case () which is inside a for() loop which is inside an if() and I need to return outside ALL of that nesting to properly determine the Remote Command sent. My testing seems to produce conflicting results regarding to where the return 'returns to'. So I am inclined to use a 'goto' label which is frowned upon. Comments? I can post the actual code (summarized to help here if necessary). Yes, I suspect that such code is very poorly structured for someone like you but I only have myself at this point.

Not what I would do. In a PID loop or similar time-critical place I would use something like the following, where check_for_control_C() peeks into the serial input buffer. The entire check should not take more than a couple of microseconds.

if (Serial.available()) {
if (check_for_control_C()) abort();  //if ^C entered, set a flag for the loop to abort.
}

The abort function could set a global flag that is checked elsewhere in the PID loop, or it could do something drastic like turn off the motor power, execute a processor reset, etc.

re: return from functions: For help with structuring your code, post the code.

Before code post, this question. Is the Serial.available() buffered, i.e. 'latched' permitting an if() test at some time later? It is this issue that has caused my much concern if it is not buffered. I think you are implying that it is. YES/NO?
Your replies are much appreciated.

Serial.available() simply tells you how many characters are in the receive input buffer, which is populated by the receive ISR.

If you remove characters by using Serial.read(), the character count resulting from the next call to Serial.available() will be correspondingly reduced.

It is easy to test these things by yourself, so do some experiments.

OK understood. I will then assume that the receive ISR has buffered that some number of characters are 'available' whenever I get to testing for them using the Serial.available().
Curious why your code suggestion using the IF in the PID loop is your preference rather than have the PID controller inside the WHILE. I should have been more precise; I use a DO/WHILE loop configuration wrapping the PID Controller. This seems essentially the same "logically" to the approach you used. Now I will do some testing before I 'bother' with my code approach. Cheers, eddy

It makes sense to me to test for emergency conditions within the inner loop, which is executed most often and rapidly.

Since you haven't posted your code, this discussion is entirely theoretical.

Of course, hypothetically discussion. In my code the test for emergencies would occur at the identical point but I will spare your time for more discussion about the actual code until I complete tests and I thank you very much.

It's hard to believe that anything that physically moves around would be very sensitive to delays in responding to an input. How far is the thing going to travel in a millisecond? But if this is really an issue, you don't have to use the built-in serial routines (Serial.begin etc). You can set up the serial port in your own code and catch the interrupts as characters arrive, and then you'd get data more quickly. Just be aware that if your code is in an interrupt, you won't get a response to RX until you exit that interrupt. Well, even that has a cure; you can re-enable interrupts while you're actually in an interrupt, but it's not a recommended way to write code.

That is EXACTLY what the Arduino core does.

Did you skip the earlier part of this discussion, where all this was carefully explained?

For the fastest possible emergency response, trapping a serial input is a poor choice. A button or other signal on an external interrupt would be much easier to implement.

Well, a hypothetical "improved" serial driver could trap control-C (or whatever) and set a separate "pending" call to test (or a callback), permitting "emergency stop" while buffering normal text for later processing. Like mainframes used to do. The current Serial.available() only tells you if ANY data is available.

I've been contemplating higher-level Serial functions for a while - the hoops in "Serial input basics" are a bit daunting for a user who wants some sort of line or text based UI.
But I hadn't considered interrupt characters, demonstrating what an open-ended "problem" "improving" things can be.

You evidently missed my point. What the Arduino does is catch the arriving characters in an interrupt, then stuff them into a buffer, which user code can check with Serial.available() and then get the data out with Serial.read(). It would be possible to write one's own interrupt for RX, and check the characters immediately on arrival. If a single character means "emergency stop" then it could be acted on much faster that way, but with a moving vehicle, I can't see it making any useful difference.

I completely understood your point. The Arduino core is open source, and anyone would be welcome to modify it to trap a character in the serial input ISR. It would take a couple of lines of code.

We are in agreement that this is a pointless exercise.

"Much faster" is in doubt. As people have said Serial.available() is quite fast.

As I started this discussion and watched it progress, I would like to state that my issue was(is) that I could not determine, even though the Hardware Serial is interrupt driven, howto find out how to set up an ISR to utilize that interrupt. JR discussed just how quickly Serial.available() can be executed when I "polled" it and that a "true" result was buffered until I did poll it. That way I would not miss the character(s) received by the Hardware Serial.

Clearly, the documentation did not state or stated it such that I misunderstood it that I didn't have to be polling the Serial port in a timely manner. Thus, I can let the PID controller operate and at the end of a single loop of that PID controller I can: "if(Serial3.available()) { /*read the buffer to determine if it is a new command or an emergency stop */}
I appreciate that the PID loop time is long (25msec) but the code should NOT take advantage of that speed AND most critically, I wanted all the critical code to be interrupt driven to train the students that were in my class. My confusion over the Hardware Serial is based on what I could find out. Thus, the forum topic that you are reading and to which you are responding. JR's replies are very helpful to me and I don't have to write anything beyond that which the Mega Serial# supports.

"Much faster" is in doubt. As people have said Serial.available() is quite fast.

The Serial.available() call may be fast when it occurs, but it only happens when the user's code reaches that point. Obviously if it's important then the user will check it frequently, but even then--an interrupt already happened at some time in the past, in order to load the incoming data into the buffer! I don't know why I'm wasting my time (my real valuable human time) on something so obvious.

Unfortunately, the answer there is that since the Arduino core already services the serial interrupts, it's next to impossible to utilize the interrupt from the user program.

Yes, I agree with this point but given that it is available at a later time will work for this project. Let me take another direction. Given all the robotic projects that DO require timely input from a remote controller, can you suggest a wifi hardware scheme for Arduino. I am currently exploring ESP32 and its ESP-NOW WiFi because it is described as peer-to-peer and low latency.