Cyclic Redundancy Check (CRC) is an error-detecting code widely used in digital networks and storage devices to detect accidental changes to raw data. Writing a CRC program in C involves calculating a CRC value for a given input data stream and verifying its integrity during transmission or storage.
In this article, we will cover the basics of CRC, the algorithm behind it, and how to implement it in C.
What is CRC?
CRC is a mathematical operation used to detect errors in a data stream. It works by treating the input data as a binary number and performing division by a predefined polynomial divisor. The remainder from this division is called the CRC value, which is appended to the original data. When the data is received, the receiver recalculates the CRC. If the remainder matches the appended CRC, the data is considered error-free.
Key Components of CRC
- Data Stream: The binary input data to be checked.
- Polynomial Divisor: A predefined binary polynomial (e.g.,
1101
for CRC-3). - Initial Value: The starting value of the CRC register (commonly
0
or1
). - Final XOR Value: A value optionally XORed with the CRC at the end.
- CRC Width: The number of bits in the CRC (e.g., CRC-8, CRC-16, CRC-32).
Steps to Calculate CRC
- Append
n
zero bits to the data, wheren
is the degree of the polynomial. - Perform bitwise division of the data by the polynomial using XOR operations.
- The remainder from this division is the CRC value.
- Append the CRC value to the original data for transmission.
Implementation of CRC in C
Here’s a simple implementation of CRC in C using a predefined polynomial:
Example: CRC-4 Implementation
#include <stdio.h>
#include <string.h>
#define POLYNOMIAL 0b1101 // Example polynomial (CRC-4)
// Function to calculate CRC
unsigned int calculateCRC(unsigned char data[], int length) {
unsigned int crc = 0; // Initialize CRC value
for (int i = 0; i < length; i++) {
crc ^= (data[i] << 3); // Align data with the CRC width (4 bits in this case)
// Perform division using the polynomial
for (int j = 0; j < 8; j++) { // 8 bits per byte
if (crc & 0x8) { // If the leftmost bit is 1
crc = (crc << 1) ^ POLYNOMIAL;
} else {
crc <<= 1;
}
}
}
return crc & 0xF; // Return the last 4 bits (CRC-4)
}
int main() {
unsigned char data[] = {0xD2, 0x3F}; // Example data
int length = sizeof(data) / sizeof(data[0]);
// Calculate CRC
unsigned int crc = calculateCRC(data, length);
// Display result
printf("CRC: 0x%X\n", crc);
return 0;
}
Explanation of the Code
- Polynomial: The
POLYNOMIAL
variable defines the divisor for CRC. For CRC-4, the example polynomial is1101
(binary). - Shifting and XOR: Data bits are aligned with the polynomial and then divided using XOR operations.
- Final CRC Value: The remainder after all iterations represents the CRC.
Example Output
If you run the above program with the data {0xD2, 0x3F}
, the output might look like this:
CRC: 0xE
Here, 0xE
is the CRC-4 value for the given data.
Adapting the Code for Other CRC Variants
To calculate other CRC variants like CRC-8, CRC-16, or CRC-32, you can:
- Change the polynomial to match the desired CRC variant.
- Adjust the CRC width and mask accordingly (e.g.,
0xFF
for CRC-8,0xFFFF
for CRC-16). - Modify the alignment (
<< n
) based on the width.
Example: CRC-16 Polynomial
For CRC-16, a common polynomial is 0x1021
. You would update the polynomial and adjust the mask:
#define POLYNOMIAL 0x1021
#define CRC_WIDTH 16
Writing a CRC program in C requires understanding the bitwise operations and the polynomial used for the calculation. The example above provides a simple implementation for CRC-4, but you can adapt it for other CRC variants by changing the polynomial and adjusting the logic. CRC is a critical tool for error detection, and implementing it in C is both a practical exercise and a valuable skill in system programming.