USB Serial connection - CRC/checksum?

I have a very fundamental question regarding the implementation of the USB Serial connection. I am using the Arduino to communicate with a computer, currently using the Win32 API. Right now I am just sending single bytes to trigger commands on the microcontroller.

Since the application is controlling a machine where I would like to assure maximum safety and avoid communication errors, I was thinking about implementing additional error detection. Is this useful or even necessary on arduino? Or are such checks already implemented on the USB level maybe? How are the lower layers of the connection built?

I'd be very grateful if someone could shed some light on this :slight_smile:

For checking integrity of a single byte I would just use a checksum, CRC seems pretty overkill to me.

I think USB has built-in error detection, but there's nothing between the USB/Serial chip and the AVR (assuming you're using a board with a separate USB/Serial chip.) That's a pretty short wire, so it ought to be pretty reliable, but ... could be subject to dropping characters if the AVR is "busy" or something.

For checking integrity of a single byte I would just use a checksum, CRC seems pretty overkill to me.

A checksum of a single byte is just repeating the byte, right? Send it three times and you can have a vote!

(although neither will correct dropped messages.)

westfw:
A checksum of a single byte is just repeating the byte, right? Send it three times and you can have a vote!

In the strictness sense, I suppose yes.

More often than not you see the checksum set so the overall sum across the entire packet (including the checksum byte) is some defined value. 0x00 or 0xFF are not uncommon choices.

(deleted)

I use a single byte CRC (CRC-8) calculation based on the polynomial 0x9B for detecting packet corruption with SerialTransfer.h with great results. It’s also super fast if you use a lookup table for CRC calculation. Here’s the code I use for CRC calculations:

#pragma once
#include "Arduino.h"




class PacketCRC
{
public: // <<---------------------------------------//public
	uint8_t poly = 0;




	PacketCRC(const uint8_t &polynomial=0x9B, const uint8_t &crcLen=8)
	{
		poly      = polynomial;
		crcLen_   = crcLen;
		tableLen_ = pow(2, crcLen);
		csTable   = new uint8_t[tableLen_];

		generateTable();
	}

	void generateTable()
	{
		for (int i = 0; i < tableLen_; ++i)
		{
			int curr = i;

			for (int j = 0; j < 8; ++j)
			{
				if ((curr & 0x80) != 0)
					curr = (curr << 1) ^ (int)poly;
				else
					curr <<= 1;
			}

			csTable[i] = (byte)curr;
		}
	}

	void printTable()
	{
		for (int i = 0; i < tableLen_; i++)
		{
			Serial.print(csTable[i], HEX);

			if ((i + 1) % 16)
				Serial.print(' ');
			else
				Serial.println();
		}
	}

	uint8_t calculate(const uint8_t &val)
	{
		if (val < tableLen_)
			return csTable[val];
		return 0;
	}

	uint8_t calculate(uint8_t arr[], uint8_t len)
	{
		uint8_t crc = 0;
		for (uint16_t i = 0; i < len; i++)
			crc = csTable[crc ^ arr[i]];

		return crc;
	}




private: // <<---------------------------------------//private
	uint16_t tableLen_;
	uint8_t  crcLen_;
	uint8_t* csTable;
};