2

I'm trying to calculate the CRC of a one byte data input using the CRC calculation unit of the stm32l152.
The CRC unit accepts only 32Bit inputs. I was able to get it calculate the CRC for a 32Bit data input, but now I'm struggling to get it to work for a byte data input.

My test input data is 0x20 and I expect as output 0xD62B0954
CRC parameter: polynom 0x04C11DB7, init-val: 0xFFFFFFFF

How can I solve this, I'm running out of ideas?

Sample code for the 32 bit data:

CRC->DR = u32Input`  
u32Crc = CRC->DR;

I've also found this code snippet, to calculate the CRC byte-wise, but the output is different.

static uint32_t crc32_step(uint32_t crc, uint8_t data)
{
    crc = ~crc ^ data;
    CRC->DR = (~CRC->DR) ^ __RBIT(~(crc << 24));
    return (crc >> 8) ^ ~__RBIT(CRC->DR);
}

I get the following output using the code above with a provided crc of 0xFFFFFFFF: 0xC491DF37

I don't really understand what the crc32_step function does, but I'm not even sure if this is the right direction to go. I would greatly appreciate any hints or ideas.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
david
  • 168
  • 1
  • 11
  • You would need some code to roll back the effects of the trailing 24 zero bits. However, it would probably be easier to calculate the CRC in software (or use this software routine to update the CRC for the trailing bytes of a block whose length is not divisible by 4). Software CRC routines often use a look-up table for speed, but can be implemented without a look-up table by processing each data bit individually. – Ian Abbott Dec 11 '20 at 13:54
  • Does the CRC unit in the stm32 uses the CRC32? if so, isn't it a bit overkill to use it for single byte check? As @IanAbbott mentions, i would go for a software implementation with table or without it. – armengedon Dec 11 '20 at 13:57
  • @armengedon I agree that would be a bit of an overkill, but its only part of the story. Actually I'm using the CRC unit first to calculate 32-bit data chunks and only for the remaining bytes, which do not make up a double word, I need a solution to calculate byte wise. A sw solution seems to be a viable solution. Preferably without lookup table, to safe memory. The performance penalty should not be too bad, because there will be at max. 3 bytes to calc. the CRC from. – david Dec 11 '20 at 14:22
  • For computing a CRC in chunks (for example, zero or more "hardware" chunks followed by zero or one, trailing "software" chunk), some CRC implementations may require the CRC bits to be XORed with an all-ones value (i.e. bit-flipped) between the chunks, and/or after the final chunk. – Ian Abbott Dec 11 '20 at 15:14
  • Please provide the CRC of 32 bits of data and that data. It can be any data. The device can be configured to compute a wide range of possible CRCs. – Mark Adler Dec 11 '20 at 18:49

2 Answers2

1

The CRC being calculated appears to be a CRC-32/MPEG2. Here is some simple code in C to calculate it:

#include <stddef.h>
#include <stdint.h>

uint32_t crc32mpeg2(uint32_t crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0xffffffff;
    while (len--) {
        crc ^= (uint32_t)(*data++) << 24;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
    }
    return crc;
}

The routine is called with NULL for mem to get the initial CRC value. So it would be used like this:

#include <stdio.h>

int main(void) {
    unsigned char data[1] = { 0x20 };
    uint32_t crc = crc32mpeg2(0, NULL, 0);
    crc = crc32mpeg2(crc, data, 1);
    printf("%08x\n", crc);
    return 0;
}

The output is:

d62b0954
Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Thanks for your code, it works nicely. You where right about the CRC-32/MPEG2 assumption. I'll accept this answer, as it solves my problem. There seems to be no solution by using the CRC unit. – david Dec 16 '20 at 07:57
  • For one to three bytes, the software solution should be adequate. If you can afford 1KB of memory for a table, you can make it quite a bit faster if needed. – Mark Adler Dec 16 '20 at 16:57
0

The most efficient way to calculate crcs in software is to use a table and doing the calculations eight bits at a time. Below is a table that allows you to calculate these:

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

static uint32_t crc32mpeg2_table[] = {
    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
    0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
    0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
    0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
    0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
    0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
    0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
    0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
    0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
    0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
    0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
    0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
    0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
    0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
    0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
    0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
    0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
    0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
    0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
    0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
    0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
    0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
};

uint32_t crc32mpeg2(uint32_t state, uint8_t *buff, size_t buff_sz)
{
    while (buff_sz-- > 0) {
        int index = (state >> 24) ^ *buff++;
        state <<= 8;
        state ^= crc32mpeg2_table[index];
    }
    return state;
}

/* this main() function to demonstrate that the crc 
 * applied to a string with a single space character works */
int main()
{
    uint8_t buff[] = { 0x20 };
    uint32_t crc = crc32mpeg2(0xffffffff, buff, sizeof buff);
    printf("0x%08x\n", crc);
}

As you can see, the result, after aplying it to your input buffer is the expected value:

$ ./crcmpg3 
0xd62b0954
$ _

To generate the table, you can just run the proposed algorithm by Mark Adler (@MarkAdler) in his response, for the full set of possible input bytes (from 0x00 to 0xff) as in:

#include <stddef.h>
#include <stdio.h>
#include <stdint.h>

/* this is the function provided by Mark in his response */
uint32_t crc32mpeg2(uint32_t crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0xffffffff;
    while (len--) {
        crc ^= (uint32_t)(*data++) << 24;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
    }
    return crc;
}

int main()
{
    int i;
    char *sep = "uint32_t crc32mpeg2_table[] = {\n\t";
    for (i = 0; i < 256; i++) {
        status = crc32mpeg2(i & 0xff, &ch, sizeof ch);
        printf("%s0x%08x", sep, status);
        sep = i % 8 == 7 ? ",\n\t" : ", ";
    }
    printf("\n};\n");
}

It will produce the table above. Once you have the table, you just need to use this function (far more quick, as you operate one full byte per iteration) to get the result:

uint32_t crc32mpeg2(uint32_t state, uint8_t *buff, size_t buff_sz)
{
    while (buff_sz-- > 0) {
        int index = (state >> 24) ^ *buff++;
        state <<= 8;
        state ^= crc32mpeg2_table[index];
    }
    return state;
}

The correct use of the function is to call it by passing the old state (which is the CRC upto the last byte processed) to get the new state (the new CRC after processing a new bunch of bytes) The first value for the state must be initialized to 0xffffffff, so to calculate the CRC of "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." you can use this main:

#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main()
{
    /* first piece */
    char *s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, ";
    uint32_t crc = crc32mpeg2(0xffffffff, s, strlen(s)); /* intialize with 0xffffffff */
    printf("CRC(\"%s", s);

    /* second piece */
    s = "sed do eiusmod tempor incididunt ut labore et dolore ";
    crc = crc32mpeg2(crc, s, strlen(s));
    printf("%s", s);

    /* third piece */
    s = "magna aliqua.";
    crc = crc32mpeg2(crc, s, strlen(s));
    printf("%s\") => ", s);

    /* print crc of the whole string */
    printf("0x%08x\n", crc);
}

which should output:

$ crcmpg3.c
CRC("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") => 0x81e9201f
$ _

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • There is even a way to pre-calculate the table(s) by the preprocessor. I have done this for several C compilers, but unfortunately it is closed-source. – the busybee Dec 16 '20 at 21:29