Close

Resiliency on UART data - implementing CRC

A project log for Direct UV Printer for Alternative Photography

Design of a UV printer for making exposures of Alternative Photography prints, direct from a digital image

david-brownDavid Brown 08/09/2016 at 02:580 Comments

The communication system between the controller (rPiZero) and print head (Arduino) I decided to simplify the code in the head by using low level functions. These take the hex code strings and pass them directly to the devices or trigger other functions. This allows flexibility and reduces the data that needs to be sent.

I've chosen a standard of 6 byte string with the first byte being the command, then up to four data bytes and finally a CRC byte.

When designing the communication between the head and the raspberry pi, I decided to include a level of error checking on the data passed, as my initial testing showed that signal integrity may be an issue. This has not proven to be a problem thus far. Anyway having a check is good practice. Also the setup process is not a time critical process but one bit wrong could cause problems with setup of the laser diode DACs and thus possible damage to the damage (means I can't blame my typos on interference).

In my research in learning about CRCs I've found the following references useful;

The linked paper is interesting as the author has investigated the design space for a huge range of data lengths and code lengths, with the resulting corruption bit length protection. It turns out that the selection of CRC code has a huge impact on the resiliency afforded.

Whilst i'm not gong to try and explain how CRCs work; see the links and your own searches. Essentially there is a balance between the number of bits protected, the number of errors detected and the number of bits in the CRC polynomial.

In my case there is 5x 8bits of data (40bits), i'm using standard 8bit bytes so the CRC can be up to 8bits (may as well use them all). So in my case the 8-bit polynomial 0x83 also known as ATM-8 or CRC-8P is the bet option as it give protection of noticing if up to 4 bits are corrupted and is good for up to 119bits of data length.

If I could send only 7bits easily for the code I would thus use the polynomial 0x5B also known as CRC-7F/4.2 which can protect up to 56bits. This would then save 1bit per transmission/packet which in some situations may be a worth while saving.

Code - Arduino / C++ (good for both TX & RX)

/*=========================================================================================*/
/* ----------------------CRC ATM-8 check------------------------------*/
/*=========================================================================================*/

uint8_t crcTable[256]; //storage of CRC lookup table

void CalulateTable_CRC8() //fill table
{
  uint8_t generator = 0x83; //ATM-8 CRC (8bit)
  // iterate over all byte values 0- 255
  for (int divident = 0; divident < 256; divident++)
  {
    uint8_t currByte = divident; 
    //calculate the CRC-8 value for current byte
    for (uint8_t bitSec = 0; bitSec < 8; bitSec++)
    {
      if ((currByte & 0x80) != 0)
      {
        currByte <<= 1;
        currByte ^= generator;
      }
      else
      {
        currByte <<= 1;
      }
    }
    //store CRC value in lookup table
    crcTable[divident] = currByte;
  }

  return;
}


uint8_t computeCRC(uint8_t message[], int nBytes)
{
  uint8_t crc = 0x0;

  for (int b = 0; b < nBytes; ++b)
  {
    //XOR in next input byte
    uint8_t data = message[b] ^ crc;
    //get current CRC value = remainder
    crc = crcTable[data];
  }
  
  return crc;
}

Discussions