Cyclic Redundancy Check (CRC)

1. Introduction

CRC is a technique to detect errors in data. It is widely used in communication systems to detect errors in data transmission. It is also used in data storage systems to detect errors in stored data. It is a type of hash function that takes an input data stream and produces a fixed-size hash value. The hash value is used to detect errors in the data stream. The hash value is appended to the data stream before transmission. The receiver calculates the hash value of the received data stream and compares it with the hash value received. If the hash values match, the data stream is considered error-free. If the hash values do not match, an error is detected.

2. Types of CRC

There are many types of CRC algorithms. The most common types are CRC-8, CRC-16, and CRC-32. The number in the name of the CRC algorithm represents the size of the hash value produced by the algorithm. For example, CRC-8 produces an 8-bit hash value, CRC-16 produces a 16-bit hash value, and CRC-32 produces a 32-bit hash value.

3. Understanding CRC

The algorithm works by dividing the input data stream by a fixed polynomial. The remainder of the division is the hash value.

3.1. CRC Polynomials

Many industries have standardized on specific polynomials for compatibility and proven reliability.

CRC Polynomials

Name

Polynomial

Hex

Applications

CRC-8-SMBUS

\(x^8 + x^2 + x + 1\)

0x07

Automotive, SMBus

CRC-16-IBM

\(x^{16} + x^{15} + x^2 + 1\)

0x8005

IBM, ZMODEM

CRC-16-CCITT

\(x^{16} + x^{12} + x^5 + 1\)

0x1021

Telecommunications, Bluetooth

CRC-32-ISO

\(x^{32} + x^{26} + x^{23} + x^{22} + x^{16} + x^{12} + x^{11} + x^{10} + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1\)

0x04C11DB7

Ethernet, ZIP files

CRC-64-ISO

\(x^{64} + x^4 + x^3 + x + 1\)

0x1B

Data storage, digital signatures

See more at crccalc or at wikipedia.

Note

The actual length of the polynomial is one bit longer than the number of bits in the CRC. The most significant bit (MSB) is always 1. So, it is not included in the polynomial.

3.2. CRC Calculation

The simplest CRC algorithm is the CRC-8 algorithm. CRC can be expensive to calculate on real-time systems. So, it is better to use a lookup table.

Generating lookup table for CRC-8:

uint8_t poly = 0x07;
// Do you know? The actual polynomial for CRC-8 is 9-bit long. But, the MSB is always 1. So, it is not included in the polynomial.

uint8_t remainder;
uint8_t crc8_table[256];

for (int dividend = 0; dividend < 256; ++dividend)
{
    remainder = dividend;
    for (int b = 8; b > 0; --b)
    {
        if (remainder & (1 << 7))  // if MSB is 1
        {
            remainder = (remainder << 1) ^ poly; // XOR with polynomial. The MSB is removed because, (MSB of remainder i.e. 1) ^ (MSB of 9-bit polynomial i.e. 1) = 0 always.
        }
        else
        {
            remainder = (remainder << 1); // left shift till MSB becomes 1
        }
    }
    crc8_table[(uint8_t)dividend] = remainder; // remainder is the CRC value of dividend
}

All the CRC value of 0-256 is stored in the table with the index as the dividend. For one byte data, the CRC is always in the table and is super easy. But for array, the remainder(CRC) of first byte (from table) is xored with the second byte, and the resulting value acts as dividend whose remainder(CRC from table) xored with third byte and so on. The remainder(CRC) of final byte calculated through this process is the remainder(CRC) of the whole array.

Calculating CRC-8 of array using lookup table:

uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05}; // input data

uint8_t dividend;
uint8_t remainder = 0;

for (int index = 0; index < len; ++index)
{
    dividend = data[index] ^ remainder;
    remainder = crc8_table[dividend];
}

printf("CRC-8: 0x%02X\n", remainder);

Please see this article and go through it to understand the CRC algorithm in detail. Take your time. Get a good understanding of the algorithm. This article is the best one, I have found on the internet.

After you know CRC-8, now it easy to understand other type. CRC8-8 is worth for small size of data but for bigger chunk or less collision, CRC-16 or CRC-32 are used.

Generating lookup table for CRC-16:

uint16_t poly = 0x1021;
uint16_t remainder;
uint16_t crc16_table[256];

for (int dividend = 0; dividend < 256; ++dividend)
{
    remainder = dividend << 8; // This is the difference from CRC-8. The 8 bits are aligned to MSB of 16-bit. For CRC-32, it is shifted left by 24;
    for (int b = 8; b > 0; --b)
    {
        if (remainder & (1 << 7))  // if MSB is 1
        {
            remainder = (remainder << 1) ^ poly; // XOR with polynomial. The MSB is removed because, (MSB of remainder i.e. 1) ^ (MSB of 9-bit polynomial i.e. 1) = 0 always.
        }
        else
        {
            remainder = (remainder << 1); // left shift till MSB becomes 1
        }
    }
    crc16_table[(uint8_t)dividend] = remainder; // remainder is the CRC value of dividend
}

Calculating CRC-16 of array using lookup table:

uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05}; // input data

uint8_t dividend;
uint16_t remainder = 0;

for (int index = 0; index < len; ++index)
{
    dividend = data[index] ^ (remainder >> 8); // For CRC-16, remainder have to be shifted right by 8. For CRC-32, it is 24.
    remainder = crc16_table[dividend];
}

printf("CRC-16: 0x%04X\n", remainder);

You got the idea. Now, you can generate the lookup table for CRC-32 and calculate the CRC-32 of the data. The are also some parameters like initial value, final XOR value, input reflected, output reflected and check value, which can be used to improve the CRC calculation. But, the above code is the basic one.

4. Implementing CRC in C++

Let’s implement the CRC algorithm in C++ using template class. I hope you have basic knowledge of C++ programming. In embedded programming, use of C++ standard library (eg: iostream, std::vector) is not recommended. Create and copy these three files.

crc.hpp:

  1/**
  2 * @file crc.hpp
  3 * @brief Header file for the CRC template class, providing support for CRC computation with customizable parameters.
  4 *
  5 * This file defines a template class for calculating CRC (Cyclic Redundancy Check) with support for reflection and various CRC types.
  6 *
  7 * @details
  8 * The `CRC` template class supports 8-bit, 16-bit, and 32-bit CRC calculations with configurable polynomials,
  9 * initial values, final XOR values, and input/output bit reflections. It includes functionality for table generation
 10 * and bit reflection. The default configuration values and polynomial constants for common CRC types (e.g., CRC-8 SMBus,
 11 * CRC-16 CCITT, CRC-32 ISO) are also provided.
 12 *
 13 * @note
 14 * This implementation enforces compile-time type checks to ensure only valid CRC types are used.
 15 *
 16 * @author
 17 * Sagar Chaudhary
 18 *
 19 * @date
 20 * 2024
 21 */
 22
 23#ifndef CRC_HPP
 24#define CRC_HPP
 25
 26#include <stdint.h>
 27#include <stddef.h>
 28#include <assert.h>
 29#include <type_traits>
 30
 31/**
 32 * @typedef CRC8_Type
 33 * @brief Defines an 8-bit CRC type.
 34 */
 35using CRC8_Type = uint8_t;
 36
 37/**
 38 * @typedef CRC16_Type
 39 * @brief Defines a 16-bit CRC type.
 40 */
 41using CRC16_Type = uint16_t;
 42
 43/**
 44 * @typedef CRC32_Type
 45 * @brief Defines a 32-bit CRC type.
 46 */
 47using CRC32_Type = uint32_t;
 48
 49// Definitions of some CRC standards
 50#define CRC8_SMBUS_POLYNOMIAL 0x07      ///< Polynomial for CRC-8 SMBus
 51#define CRC8_SMBUS_INITIAL_CRC 0x00     ///< Initial value for CRC-8 SMBus
 52#define CRC8_SMBUS_FINAL_XOR 0x00       ///< Final XOR value for CRC-8 SMBus
 53#define CRC8_SMBUS_REFLECT_INPUT false  ///< Input reflection for CRC-8 SMBus
 54#define CRC8_SMBUS_REFLECT_OUTPUT false ///< Output reflection for CRC-8 SMBus
 55
 56#define CRC16_CCITT_POLYNOMIAL 0x1021    ///< Polynomial for CRC-16 CCITT
 57#define CRC16_CCITT_INITIAL_CRC 0xFFFF   ///< Initial value for CRC-16 CCITT
 58#define CRC16_CCITT_FINAL_XOR 0x0000     ///< Final XOR value for CRC-16 CCITT
 59#define CRC16_CCITT_REFLECT_INPUT false  ///< Input reflection for CRC-16 CCITT
 60#define CRC16_CCITT_REFLECT_OUTPUT false ///< Output reflection for CRC-16 CCITT
 61
 62#define CRC32_ISO_POLYNOMIAL 0x04C11DB7  ///< Polynomial for CRC-32 ISO
 63#define CRC32_ISO_INITIAL_CRC 0xFFFFFFFF ///< Initial value for CRC-32 ISO
 64#define CRC32_ISO_FINAL_XOR 0xFFFFFFFF   ///< Final XOR value for CRC-32 ISO
 65#define CRC32_ISO_REFLECT_INPUT true     ///< Input reflection for CRC-32 ISO
 66#define CRC32_ISO_REFLECR_OUTPUT true    ///< Output reflection for CRC-32 ISO
 67
 68#define CRC_VALIDATION_STRING "123456789" ///< Standard validation string for CRC
 69
 70/**
 71 * @class CRC
 72 * @brief Template class for CRC computation.
 73 *
 74 * @tparam CRC_Type The CRC type, must be one of `CRC8_Type`, `CRC16_Type`, or `CRC32_Type`.
 75 *
 76 * @details
 77 * This class allows calculation of CRC using a lookup table for improved performance.
 78 * It supports customizable parameters such as polynomial, initial value, and bit reflection.
 79 */
 80template <typename CRC_Type>
 81class CRC
 82{
 83    static_assert(std::is_same<CRC_Type, CRC8_Type>::value ||
 84                      std::is_same<CRC_Type, CRC16_Type>::value ||
 85                      std::is_same<CRC_Type, CRC32_Type>::value,
 86                  "CRC template class only supports CRC8_Type, CRC16_Type, and CRC32_Type!");
 87
 88public:
 89    CRC();
 90    CRC(CRC_Type polynomial, CRC_Type initial_crc = 0, const CRC_Type final_xor = 0,
 91        bool reflect_input = false, bool reflect_output = false);
 92    
 93    CRC(const CRC &) = delete;
 94    CRC &operator=(const CRC &) = delete;
 95    
 96    static CRC_Type reflect_bits(CRC_Type value, int num_bits);
 97    CRC_Type compute_hash(const uint8_t *data, const size_t len) const;
 98    
 99    void print_table() const;
100
101    // Getters for class members
102    const CRC_Type get_polynomial() const;  ///< Get the polynomial used for CRC.
103    const CRC_Type get_initial_crc() const; ///< Get the initial CRC value.
104    const CRC_Type get_final_xor() const;   ///< Get the final XOR value.
105    const CRC_Type *get_table() const;      ///< Get the CRC lookup table.
106    const CRC_Type get_check() const;       ///< Get the validation CRC value.
107
108    static constexpr int width = sizeof(CRC_Type) * 8; ///< CRC width in bits.
109
110private:
111    void initialize();    ///< Initialize CRC parameters.
112    void compute_table(); ///< Compute the CRC lookup table.
113
114    const CRC_Type polynomial_;  ///< Polynomial for CRC calculation.
115    const CRC_Type initial_crc_; ///< Initial CRC value.
116    const CRC_Type final_xor_;   ///< Final XOR value.
117    const bool reflect_input_;   ///< Input bit reflection flag.
118    const bool reflect_output_;  ///< Output bit reflection flag.
119    CRC_Type table_[256];        ///< Lookup table for CRC calculation.
120    CRC_Type check_;             ///< Validation CRC value.
121};
122
123#include "crc.tpp"
124
125#endif // CRC_HPP

crc.tpp:

  1/**
  2 * @file crc.tpp
  3 * @brief Inline implementation file for the CRC template class.
  4 * 
  5 * This file contains the inline implementation of the CRC template class, 
  6 * including methods for bit reflection, table computation, and CRC calculation.
  7 * 
  8 * @ref https://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
  9 * 
 10 * @details
 11 * The CRC template class supports computation of CRC values for 8-bit, 16-bit, 
 12 * and 32-bit types. This file includes the reflection function, constructors 
 13 * for default and parameterized configurations, table initialization, and the 
 14 * main hash computation function. Additionally, the CRC lookup table can be printed 
 15 * for debugging or validation purposes.
 16 * 
 17 * @note
 18 * Ensure that the CRC polynomial is non-zero when using the parameterized constructor.
 19 * 
 20 * @warning
 21 * The CRC template does not allow copy construction or assignment.
 22 * 
 23 * @author 
 24 * Sagar Chaudhary
 25 * 
 26 * @date 
 27 * 2024
 28 */
 29
 30#include <string.h>
 31#include <stdio.h>
 32
 33#include "crc.hpp"
 34
 35/**
 36 * @brief Default constructor for CRC-8 configuration.
 37 */
 38template <>
 39CRC<CRC8_Type>::CRC()
 40    : polynomial_(CRC8_SMBUS_POLYNOMIAL),
 41      initial_crc_(CRC8_SMBUS_INITIAL_CRC),
 42      final_xor_(CRC8_SMBUS_FINAL_XOR),
 43      reflect_input_(CRC8_SMBUS_REFLECT_INPUT),
 44      reflect_output_(CRC8_SMBUS_REFLECT_OUTPUT)
 45{
 46    this->initialize();
 47}
 48
 49/**
 50 * @brief Default constructor for CRC-16 configuration.
 51 */
 52template <>
 53CRC<CRC16_Type>::CRC()
 54    : polynomial_(CRC16_CCITT_POLYNOMIAL),
 55      initial_crc_(CRC16_CCITT_INITIAL_CRC),
 56      final_xor_(CRC16_CCITT_FINAL_XOR),
 57      reflect_input_(CRC16_CCITT_REFLECT_INPUT),
 58      reflect_output_(CRC16_CCITT_REFLECT_OUTPUT)
 59{
 60    this->initialize();
 61}
 62
 63/**
 64 * @brief Default constructor for CRC-32 configuration.
 65 */
 66template <>
 67CRC<CRC32_Type>::CRC()
 68    : polynomial_(CRC32_ISO_POLYNOMIAL),
 69      initial_crc_(CRC32_ISO_INITIAL_CRC),
 70      final_xor_(CRC32_ISO_FINAL_XOR),
 71      reflect_input_(CRC32_ISO_REFLECT_INPUT),
 72      reflect_output_(CRC32_ISO_REFLECR_OUTPUT)
 73{
 74    this->initialize();
 75}
 76
 77/**
 78 * @brief Parameterized constructor for CRC configuration.
 79 * 
 80 * @param polynomial The polynomial for CRC calculation.
 81 * @param initial_crc The initial CRC value.
 82 * @param final_xor The final XOR value.
 83 * @param reflect_input Flag to enable input bit reflection.
 84 * @param reflect_output Flag to enable output bit reflection.
 85 */
 86template <typename CRC_Type>
 87CRC<CRC_Type>::CRC(CRC_Type polynomial, CRC_Type initial_crc, CRC_Type final_xor,
 88                   bool reflect_input, bool reflect_output)
 89    : polynomial_(polynomial),
 90      initial_crc_(initial_crc),
 91      final_xor_(final_xor),
 92      reflect_input_(reflect_input),
 93      reflect_output_(reflect_output)
 94{
 95    if (polynomial == 0)
 96        printf("ERROR::CRC polynomial cannot be zero\n");
 97
 98    this->initialize();
 99}
100
101/**
102 * @brief Initializes the CRC instance, including table computation and validation.
103 */
104template <typename CRC_Type>
105inline void CRC<CRC_Type>::initialize()
106{
107    this->compute_table();
108
109    const char crc_validation_string[] = CRC_VALIDATION_STRING;
110    this->check_ = this->compute_hash((uint8_t *)crc_validation_string, strlen(crc_validation_string));
111}
112
113/**
114 * @brief Reflects the bits of a value.
115 * 
116 * @tparam CRC_Type The type of the value (e.g., uint8_t, uint16_t, uint32_t).
117 * @param value The value to reflect.
118 * @param num_bits The number of bits to reflect.
119 * @return The reflected value.
120 */
121template <typename CRC_Type>
122inline CRC_Type CRC<CRC_Type>::reflect_bits(CRC_Type value, int num_bits)
123{
124    CRC_Type reflected = 0;
125    for (int i = 0; i < num_bits; ++i)
126    {
127        if (value & (1 << i))
128        {
129            reflected |= (1 << (num_bits - 1 - i));
130        }
131    }
132    return reflected;
133}
134
135/**
136 * @brief Computes the CRC lookup table.
137 */
138template <typename CRC_Type>
139inline void CRC<CRC_Type>::compute_table()
140{
141    // Calculate CRC of all 256 possible byte values.
142    for (int dividend = 0; dividend < 256; ++dividend)
143    {
144        // Align the byte to leftmost position.
145        CRC_Type remainder = dividend << (this->width - 8);
146
147        for (int bit = 8; bit > 0; --bit)
148        {
149            // Left shift till bit 1 found at MSB.
150            if (remainder & (1 << (width - 1)))
151            {
152                // XOR with polynomial if MSB is 1.
153                // The MSB of polynomial is always 1 which is not included. So, MSB polynomial ^ MSB of remainder = 0.
154                // That's why it is left lefted first then XORed to find remainder.
155                remainder = (remainder << 1) ^ this->polynomial_;
156            }
157            else
158            {
159                remainder = (remainder << 1);
160            }
161        }
162
163        // Store the remainder in the lookup table.
164        this->table_[dividend] = remainder;
165    }
166}
167
168/**
169 * @brief Computes the CRC hash for the given data.
170 * 
171 * @param data Pointer to the input data.
172 * @param len Length of the input data.
173 * @return The computed CRC value.
174 */
175template <typename CRC_Type>
176inline CRC_Type CRC<CRC_Type>::compute_hash(const uint8_t *data, const size_t len) const
177{
178    // Initialize the remainder with the initial CRC value.
179    CRC_Type remainder = this->initial_crc_;
180    uint8_t dividend;
181
182    // data cannot be nullptr.
183    if (data != nullptr)
184    {
185        // Initial CRC is XORed with first byte; the CRC of resulting is XORed with second byte and so on.
186        // The final CRC is XORed with final_xor_.
187
188        for (size_t index = 0; index < len; ++index)
189        {
190            // Reflect byte from data if enabled.
191            dividend = reflect_input_ ? reflect_bits(data[index], 8) : data[index];
192            
193            // Left most byte of remainder is XORed with data as data is one byte in each step.
194            dividend ^= (remainder >> (this->width - 8));
195
196            // CRC of resultant is taken from lookup table.
197            // Used left most byte of remainder is removed shifting left by 8.
198            // Now, XORed to find new remainder.
199            remainder = table_[dividend] ^ (remainder << 8);
200        }
201    }
202
203    // Reflect remainder if enabled and XOR with final xor value.
204    return (reflect_output_ ? reflect_bits(remainder, this->width) : remainder) ^ this->final_xor_;
205}
206
207/**
208 * @brief Prints the CRC lookup table to the console.
209 */
210template <typename CRC_Type>
211inline void CRC<CRC_Type>::print_table() const
212{
213    for (int i = 0; i < 256; ++i)
214    {
215        printf("%0*X", this->width / 4, this->table_[i]);
216
217        if ((i + 1) % 8 == 0)
218        {
219            printf("\n");
220        }
221        else
222        {
223            printf("\t");
224        }
225    }
226}

crc_testing.cpp:

 1#include <stdio.h>
 2#include <string.h>
 3#include "crc.hpp"
 4
 5int main()
 6{
 7    CRC<uint32_t> crc(0xF4ACFB13, 0xFFFFFFFF, 0xFFFFFFFF, true, true);
 8    crc.print_table();
 9    printf("check: %08X\n", crc.get_check());
10
11    char data[] = "Hello World";
12    printf("hash: %08X\n", crc.compute_hash((uint8_t*)data, strlen(data)));
13    return 0;
14}

Compile and run using your computer. To verify, use online crc calculator: sunshine2k or crccalc.

g++ crc_testing.cpp -o crc_testing
./crc_testing

Output:

00000000        F4ACFB13        1DF50D35        E959F626        3BEA1A6A        CF46E179        261F175F        D2B3EC4C
77D434D4        8378CFC7        6A2139E1        9E8DC2F2        4C3E2EBE        B892D5AD        51CB238B        A567D898
EFA869A8        1B0492BB        F25D649D        06F19F8E        D44273C2        20EE88D1        C9B77EF7        3D1B85E4
987C5D7C        6CD0A66F        85895049        7125AB5A        A3964716        573ABC05        BE634A23        4ACFB130
2BFC2843        DF50D350        36092576        C2A5DE65        10163229        E4BAC93A        0DE33F1C        F94FC40F
5C281C97        A884E784        41DD11A2        B571EAB1        67C206FD        936EFDEE        7A370BC8        8E9BF0DB
C45441EB        30F8BAF8        D9A14CDE        2D0DB7CD        FFBE5B81        0B12A092        E24B56B4        16E7ADA7
B380753F        472C8E2C        AE75780A        5AD98319        886A6F55        7CC69446        959F6260        61339973
57F85086        A354AB95        4A0D5DB3        BEA1A6A0        6C124AEC        98BEB1FF        71E747D9        854BBCCA
202C6452        D4809F41        3DD96967        C9759274        1BC67E38        EF6A852B        0633730D        F29F881E
B850392E        4CFCC23D        A5A5341B        5109CF08        83BA2344        7716D857        9E4F2E71        6AE3D562
CF840DFA        3B28F6E9        D27100CF        26DDFBDC        F46E1790        00C2EC83        E99B1AA5        1D37E1B6
7C0478C5        88A883D6        61F175F0        955D8EE3        47EE62AF        B34299BC        5A1B6F9A        AEB79489
0BD04C11        FF7CB702        16254124        E289BA37        303A567B        C496AD68        2DCF5B4E        D963A05D
93AC116D        6700EA7E        8E591C58        7AF5E74B        A8460B07        5CEAF014        B5B30632        411FFD21
E47825B9        10D4DEAA        F98D288C        0D21D39F        DF923FD3        2B3EC4C0        C26732E6        36CBC9F5
AFF0A10C        5B5C5A1F        B205AC39        46A9572A        941ABB66        60B64075        89EFB653        7D434D40
D82495D8        2C886ECB        C5D198ED        317D63FE        E3CE8FB2        176274A1        FE3B8287        0A977994
4058C8A4        B4F433B7        5DADC591        A9013E82        7BB2D2CE        8F1E29DD        6647DFFB        92EB24E8
378CFC70        C3200763        2A79F145        DED50A56        0C66E61A        F8CA1D09        1193EB2F        E53F103C
840C894F        70A0725C        99F9847A        6D557F69        BFE69325        4B4A6836        A2139E10        56BF6503
F3D8BD9B        07744688        EE2DB0AE        1A814BBD        C832A7F1        3C9E5CE2        D5C7AAC4        216B51D7
6BA4E0E7        9F081BF4        7651EDD2        82FD16C1        504EFA8D        A4E2019E        4DBBF7B8        B9170CAB
1C70D433        E8DC2F20        0185D906        F5292215        279ACE59        D336354A        3A6FC36C        CEC3387F
F808F18A        0CA40A99        E5FDFCBF        115107AC        C3E2EBE0        374E10F3        DE17E6D5        2ABB1DC6
8FDCC55E        7B703E4D        9229C86B        66853378        B436DF34        409A2427        A9C3D201        5D6F2912
17A09822        E30C6331        0A559517        FEF96E04        2C4A8248        D8E6795B        31BF8F7D        C513746E
6074ACF6        94D857E5        7D81A1C3        892D5AD0        5B9EB69C        AF324D8F        466BBBA9        B2C740BA
D3F4D9C9        275822DA        CE01D4FC        3AAD2FEF        E81EC3A3        1CB238B0        F5EBCE96        01473585
A420ED1D        508C160E        B9D5E028        4D791B3B        9FCAF777        6B660C64        823FFA42        76930151
3C5CB061        C8F04B72        21A9BD54        D5054647        07B6AA0B        F31A5118        1A43A73E        EEEF5C2D
4B8884B5        BF247FA6        567D8980        A2D17293        70629EDF        84CE65CC        6D9793EA        993B68F9
check: 1697D06A
hash: 07AAD778

5. Using STM32 CRC Hardware

STM32 microcontrollers have CRC-32 hardware. We can use it to calculate CRC-32.

Note

STM32F103C8T6 and STM32F407VGT6 CRC hardware have no configuration, so only default CRC-32 can be calculated. Their default parameters are:

  • Polynomial: 0x04C11DB7

  • Initial Value: 0xFFFFFFFF

  • Final XOR Value: None (must be applied manually if needed).

  • Reflect Input/Output: Not supported in hardware (manual reflection required).

5.1. CubeMX Setup

Generate baisc code with:

  • microcontroller: STM32F103C8T6

  • project name: crc_test

  • Toolchain/IDE: Makefile

Also enable USB for printf if ITM SWV not woriking (for bluepill using duplicate stlink which do not have SWO). See this for USB setup.

crc_test_cubemx.png

5.2. Code Implementation

Navigate to Core > Src > main.c and add the following code. Add the following includes.

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "usbd_cdc_if.h"
/* USER CODE END Includes */

Add the following test code to calculate CRC-32.

/* USER CODE BEGIN 2 */
char data[] = "123456789";
char buf[100]; // For CDC transmit
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  uint32_t crc = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
  snprintf(buf, sizeof(buf), "data: %s, crc: 0x%8lX\n", data, crc);
  // if it supports CRC Hardware configurtion
  // snprintf(buf, sizeof(buf), "POL: 0x%8lX, INIT: 0x%8lX, CRC: 0x%8lX\n", hcrc.Instance->POL, hcrc.Instance->INIT, crc);
  CDC_Transmit_FS((uint8_t*)buf, strlen(buf));
  HAL_Delay(100);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

Compile and upload the code. Open the serial terminal and you will see the CRC-32 of the data. Verify output using online CRC calculator.