Is CRC needed for USB Arduino-Computer communication?

Hello,

I would like to reliably send smallish amounts of data (around 30-40 bytes per message) to and from an Arduino Uno and a computer (Windows or Mac), using a USB cable. I wrote basic code already using Arduino’s built-in Serial library to transmit these messages, and so far it has worked perfectly without any CRC or error checking.

I know that the data should be safe when transferred over USB, since USB uses packets with CRC. However, serial communication can lose data and the Arduino Uno has a USB/serial converter, so I’m not sure if data can be lost between there and my sketch.

I tested data loss by sending 20,000 64-byte blocks of random data to the Arduino, and having it repeat back exactly what was sent after each block, and then comparing what was sent back with the original data. Without any error checking, and at 57600 baud, no data was lost (2,560,000 bytes of data total with no error). This makes me think that the Arduino does some internal error checking, but I would like to make sure of that.

Should I implement a packet and CRC system, or does the Arduino already do this for me?
Thanks!

I don’t know if it’s needed, but here is the code I used for the data loss test:
(Arduino.RawRead/RawWrite just call WinAPI’s ReadFile/WriteFile functions, and Arduino.Connect just finds the Arduino’s COM port and opens a connection)

Arduino.Connect(nullptr, COMBaudRates::B57600);
Arduino.SetReadTimeout(500);
unsigned int starttime = time(NULL);
srand(starttime);

for(unsigned int i = 0; i < 10000; i++)
{
	uint8_t random[64];
	for(size_t i = 0; i < 64; i++)
		random[i] = rand() % 255;

	if(!Arduino.RawWrite(random, 64))
		__debugbreak();
	uint8_t response[64];
	uint16_t responseSize;
	if(!Arduino.RawRead(response, 64, &responseSize, true))
		__debugbreak();
	if(responseSize != 64)
		__debugbreak();

	for(size_t i = 0; i < 64; i++)
	{
		if(random[i] != response[i])
			__debugbreak();
	}
}

Arduino side:

void setup()
{
  Serial.begin(57600);
}

void loop()
{
  while(Serial.available() > 0)
  {
    byte b = Serial.read();
    Serial.write(b);
  }
}

(sorry, long post…)

If you are using pin 1 and 2 (or the usb connection) then you are using the hardware implementation, and can assume that it is pretty reliable.

The Serial implementation in Arduino uses a 64 byte buffer, so the biggest risk you have of losing data is that the buffer overfills before you have time to process it. In your schetch you are processing the data as fast as you can, but as soon as you start adding other tasks or more processing on the received data, the more you run the risk of not being able to process it fast enough.

You can do some sums to calculate the speed or frequency at which serial data gets transmitted at various baud rates, and combine it with how much data you need to send to the processor the whole time, and figure out if your main loop is fast enough to be able to clear the buffer before 64 characters builds up.

In my opinion, this will be your biggest risk of having "corrupt" data.

Okay thanks. I knew about the buffer size, and I can account for that pretty easily in my current project. I just wanted to make sure that I wouldn't lose data to serial corruption or something like that.

How much would it matter if some data was corrupted?

If it would cause a very serious problem you need to implement some form of error detection. No transmission system is guaranteed 100% certain.

A simple XOR of all the bytes transmitted with the XOR value added as an extra byte should show if there was an error but would not be able to correct the error. Put another way, the chances of their being an error in the data that is not noticed in a mis-match of the XOR value would be very much smaller than the risk of an error when there was no checking.

More complex systems will give more certainty and can allow for error correction.

...R

The messages tell the Arduino how to control motors and other external devices, so the data is pretty important. I was planning on using CRC-8 to detect errors, but I'm not sure if that's good enough. Should I use CRC-16?

1amw31rd: The messages tell the Arduino how to control motors and other external devices, so the data is pretty important. I was planning on using CRC-8 to detect errors, but I'm not sure if that's good enough. Should I use CRC-16?

A lot depends on what you are going to do when an error is detected.

If you can just ignore the data and request a repeat I reckon even the simplest error checking will reduce the risk to a very low level.

I am saying that based on your earlier comments suggesting that the system is very reliable even with no error detection.

Perhaps you need to do some maths to decide what error probability is acceptable - for example 1 in million, 1 in 10 million, 1 in 100 million etc. Then you can study the performance of the different options to decide which suits you best.

"Better" error detection carries a cost in terms of additional calculation. In an Arduino that might start to interfere with the throughput of the "useful" part of the Arduino's job.

...R

Okay, I think I'll go with a CRC-16, since it should be able to detect almost all errors, and I can request packet repeats if an error is detected, and it should be fast enough too.

Thanks for your help :)

Another easy way to provide increased reliability is to require each command
to be repeated exactly before it is obeyed, or choose long random strings for
each command so one will not readily morph into another.