Arduino Uno Freezing After 96 bytes of IR Serial Data Received

Hello all!

Had a quick question that my colleague and I are curious about.

To set the scene (unfortunately cannot go into extreme detail), we have two IrDA2 Click Transceiver boards, one connected to the laptop through UART, and the second connected to the Tx and Rx of the Arduino Uno.

We have a string sent manually from software that is as follows:
5A 5A 5A 5A FB 4D 00 01 AB AB 10 00 C0 DE BE EF

Where the 5A bytes are sync words, FB 4D is the received checksum, 00 01 is the message ID, AB AB is the message status, 10 00 is the byte length, and C0 DE BE EF is the message data.

The code that I have attached is essentially just loopback code, where the arduino is supposed to read the serial data from the IR boards, store it in the buffer (in order), check if the data received matches (if not modify the status bytes), and then send the data back after setting the message ID to 2.
The code itself works, however we have noticed in testing it that after 96 bytes received and sent (6 messages), the arduino seems to freeze up on the Serial.write functions, and requires us to manually reset the board to have the system to continue working. We are trying to figure out the reasoning behind this, as the reset button in application will not be able to be manually touched, and just for sanity's sake. We figured it may be a memory issue (however that still for some reason doesn't seem like the cause) with memcpy function and struct layout, however we are not entirely sure, and were curious if anyone had any ideas.

The code for the loop (with struct declaration & brief setup for checksum) as is:

struct incomingMsg
{
  uint8_t sync_word1; 
  uint8_t sync_word2; 
  uint8_t sync_word3; 
  uint8_t sync_word4;
  uint16_t checksum; 
  uint16_t msgID; 
  uint16_t msgStatus; 
  uint16_t msgLeng; 
  uint32_t msgData; 
} iM;

void setup() {

  Serial.begin(115200);
  checksum = checksum_gen((uint8_t*)(&(iM.msgID)), iM.msgLeng - 6);
}

void loop() {


  byte counter = 0; //set counter for storing in buffer, cannot use msgLeng b/c it is the equivalent of the buffer

  byte buff[sizeof(incomingMsg)]; //buffer for storing message as counter increments and data is read


  if (Serial.available() > 0) {
    buff[counter++] = Serial.read();
  } //after parsing out data, need to: (1) set msgID to 2 (2) if data is incorrect, set msgStatus to 0xEAEA (3) send data back out
  memcpy(&iM, buff, sizeof(incomingMsg));

  if (iM.checksum != checksum) { //issue with original struct value, keep it with iM struct and value for checksum that is expected, checksum matches, set msgID to 2 and leave msgStatus at 0xABAB

    iM.msgStatus = 0xEAEA; //set msgStatus to EAEA to signify bad data

  }

  iM.msgID = 0x0002; //set msgID to 2 before sending back
  iM.checksum = checksum_gen(((uint8_t *)&iM) + 6, (iM.msgLeng - 6));

  Serial.write(iM.sync_word1);
  Serial.write(iM.sync_word2);
  Serial.write(iM.sync_word3);
  Serial.write(iM.sync_word4);
  Serial.write((uint8_t*)(&(iM.checksum)), 2);
  Serial.write((uint8_t*)(&(iM.msgID)), 2);
  Serial.write((uint8_t*)(&(iM.msgStatus)), 2);
  Serial.write((uint8_t*)(&(iM.msgLeng)), 2);
  Serial.write((uint8_t*)(&(iM.msgData)), 4);

}
}

Thank you in advance for your help! I have the rest of this code handy as needed, but wanted to simplify it down to where the problem resides. We redid the code (modifying the structs and swapped static bytes to bytes) so we have solved this problem, however we're curious as to why this set of code doesn't work, so if anyone has any clue it would be much appreciated!

Welcome,

counter is static, so you have to reset it to 0 somewhere

static is like a global variable, it's initialized once, not every loop()

1 Like

Thank you for the help!
I failed to mention that we did remove the static portion of those two variables, and the problem still persisted (ill update the code in the post to reflect that) but we figured that did have a definite effect on it!

  if (Serial.available() > 0) {
    buff[counter++] = Serial.read();
} //after parsing out data

Where do you check for overflow of buff?

I don't believe that we do anywhere , I think I figured that since it was only 16 bytes for the message that it wouldn't cause an issue, but we put in a Serial.flush() at the bottom of the write statements to try to flush anything left in the buffer before the loop repeats, but maybe my understanding of that is incorrect.

It is not wise to neglect such a simple safety precaution.

I can't figure out how your loop is supposed to work. The if statement I quoted in reply #4 moves only one byte, so how do you know when a complete message is received?

You might consider something like this:

  while (Serial.available() > 0 && counter < sizeof(buff) ) {
    buff[counter++] = Serial.read();
} //after parsing out data

flush() operates on the TX buffer that is maintained by the core, it can't have any effect on buffers like 'buff' that you create in your application program.

Also when you update code, just re-post it, don't go back and edit the original post.

The best time to check your buffer for overflow, is exactly when you are adding a character to it. It's not that hard to do. But another way to view it, in your case it overflows because you're not maintaining the buffer pointer properly. So although it's a little unsafe, you could still achieve a working program without checking. I suppose that means you should make it work first.

Preventing a buffer from overflowing by simply blocking it, does not address the problem of the data that you lose because you can't store it. You have to know how many characters to expect, allow for slightly more, and then consider what you will do when it overflows because that is clearly an error condition.

1 Like

There appear to be several different problems to solve, and you should probably rethink the entire approach, rather than try to fix the posted code.

Great thank you, this is basically exactly what we were looking for so I appreciate it!
More or less just needed a better understanding of why it was functional but not entirely, so that would make sense! Thank you again

Absolutely, we were aware that there we different issues (just curious as to the potential reasoning behind one in specific), and this is not the full set of the code, but I do appreciate the input so thank you!

@aarg I think some of the confusion at least on my end stemmed from the fact that I thought buffers were set in the .h files to be a max of 64 bytes, so seeing 96 causing the freeze was throwing me off

That would stem from a lack of understanding of the different role of API code vs. application code...

@aarg Still learning how to code, relatively new concept to me so yeah, likely

The tutorial, "serial input basics" really has things nailed. Have a look.