avr-chat
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-chat] Storing table in flash


From: David Brown
Subject: Re: [avr-chat] Storing table in flash
Date: Sat, 12 Jan 2008 23:47:54 +0100
User-agent: Thunderbird 2.0.0.9 (Windows/20071031)

Preston Wilson wrote:
"Kreyl" wrote:

  I'm  writing  table-based  crc16  calculation algoritm. So, I should
store this table somewhere.

  Is that enough:

const uint16_t CRC16_8005_TABLE [256] = {
0x0000,0x8005,0x800f,0x000a,0x801b,0x001e,0x0014,0x8011,0x8033,0x0036,0x003c,
...
};

  Or I need to use somewhat from <avr/pgmspace.h>? If so, how should I
do that?

Have you looked at avr-libc's crc16 routines?  They are in util/crc16.h and
are written in inline assembly, but they include the equivalent C code above
the function definition.

This is the the code from the comments/documentation for crc16_update(),
which is the routine that I think is equivalent to the one your are
implementing (depends upon how the bits are shifted in [lsb vs msb first]
and the initial value [0x0000 vs 0xffff]):

uint16_t
crc16_update(uint16_t crc, uint8_t a)
{
    int i;

    crc ^= a;
    for (i = 0; i < 8; ++i)
    {
        if (crc & 1)
            crc = (crc >> 1) ^ 0xA001;
        else
            crc = (crc >> 1);
    }

    return crc;
}

And to answer your question, you can use the table as you have defined it if
you have enough memory to do that, but as the routine above shows, crc16
checksums can be done in a much more space efficient manner.


The table defined above is stored in RAM, not flash (although obviously the initialisers are stored in flash), and thus takes up lots of valuable ram space. The routines from avrlibc are much more space efficient (no tables at all), but are much slower, since they handle a single bit at a time. I've included routines below that use 256-entry lookup tables in flash, and are therefore much faster than the avrlibc version and don't have the ram requirements of the OP's. I've also included a compromise solution - 16-entry tables, handling 4 bits at a time. I haven't actually tried this version with avrgcc - I implemented it in pure assembly many years ago, and it can be very small and tight (using "swap" instructions). It may be an interesting test case for benchmarking avrgcc.

If anyone wants to add these crc routines to avrlibc, modified to suit the avrlibc coding style, then that's fine by me.

The 8-bit crc code used is the same polynomial as the Dallas one-wire devices, though IIRC there are some differences in the algorithm (different bit order, or starting value, or something). The 16-bit crc polynomial is the common "CRC16", as used by the O/P.

mvh.,

David


/* crcTable[i] is used for byte-wise 8-bit crc routine */
static const uint8_t PROGMEM crcTable8[256] = {
        0x00, 0x8D, 0x97, 0x1A, 0xA3, 0x2E, 0x34, 0xB9,
        0xCB, 0x46, 0x5C, 0xD1, 0x68, 0xE5, 0xFF, 0x72,
        0x1B, 0x96, 0x8C, 0x01, 0xB8, 0x35, 0x2F, 0xA2,
        0xD0, 0x5D, 0x47, 0xCA, 0x73, 0xFE, 0xE4, 0x69,
        0x36, 0xBB, 0xA1, 0x2C, 0x95, 0x18, 0x02, 0x8F,
        0xFD, 0x70, 0x6A, 0xE7, 0x5E, 0xD3, 0xC9, 0x44,
        0x2D, 0xA0, 0xBA, 0x37, 0x8E, 0x03, 0x19, 0x94,
        0xE6, 0x6B, 0x71, 0xFC, 0x45, 0xC8, 0xD2, 0x5F,
        0x6C, 0xE1, 0xFB, 0x76, 0xCF, 0x42, 0x58, 0xD5,
        0xA7, 0x2A, 0x30, 0xBD, 0x04, 0x89, 0x93, 0x1E,
        0x77, 0xFA, 0xE0, 0x6D, 0xD4, 0x59, 0x43, 0xCE,
        0xBC, 0x31, 0x2B, 0xA6, 0x1F, 0x92, 0x88, 0x05,
        0x5A, 0xD7, 0xCD, 0x40, 0xF9, 0x74, 0x6E, 0xE3,
        0x91, 0x1C, 0x06, 0x8B, 0x32, 0xBF, 0xA5, 0x28,
        0x41, 0xCC, 0xD6, 0x5B, 0xE2, 0x6F, 0x75, 0xF8,
        0x8A, 0x07, 0x1D, 0x90, 0x29, 0xA4, 0xBE, 0x33,
        0xD8, 0x55, 0x4F, 0xC2, 0x7B, 0xF6, 0xEC, 0x61,
        0x13, 0x9E, 0x84, 0x09, 0xB0, 0x3D, 0x27, 0xAA,
        0xC3, 0x4E, 0x54, 0xD9, 0x60, 0xED, 0xF7, 0x7A,
        0x08, 0x85, 0x9F, 0x12, 0xAB, 0x26, 0x3C, 0xB1,
        0xEE, 0x63, 0x79, 0xF4, 0x4D, 0xC0, 0xDA, 0x57,
        0x25, 0xA8, 0xB2, 0x3F, 0x86, 0x0B, 0x11, 0x9C,
        0xF5, 0x78, 0x62, 0xEF, 0x56, 0xDB, 0xC1, 0x4C,
        0x3E, 0xB3, 0xA9, 0x24, 0x9D, 0x10, 0x0A, 0x87,
        0xB4, 0x39, 0x23, 0xAE, 0x17, 0x9A, 0x80, 0x0D,
        0x7F, 0xF2, 0xE8, 0x65, 0xDC, 0x51, 0x4B, 0xC6,
        0xAF, 0x22, 0x38, 0xB5, 0x0C, 0x81, 0x9B, 0x16,
        0x64, 0xE9, 0xF3, 0x7E, 0xC7, 0x4A, 0x50, 0xDD,
        0x82, 0x0F, 0x15, 0x98, 0x21, 0xAC, 0xB6, 0x3B,
        0x49, 0xC4, 0xDE, 0x53, 0xEA, 0x67, 0x7D, 0xF0,
        0x99, 0x14, 0x0E, 0x83, 0x3A, 0xB7, 0xAD, 0x20,
        0x52, 0xDF, 0xC5, 0x48, 0xF1, 0x7C, 0x66, 0xEB
};

/* crcTable[i] is used for byte-wise 8-bit crc routine */
static const uint16_t PROGMEM crcTable16[256] = {
        0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
        0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
        0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
        0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
        0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
        0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
        0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
        0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
        0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
        0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
        0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
        0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
        0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
        0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
        0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
        0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
        0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
        0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
        0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
        0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
        0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
        0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
        0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
        0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
        0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
        0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
        0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
        0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
        0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
        0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
        0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
        0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
};

/* When you have a full table, an 8-bit CRC routine is pretty simple! */

uint8_t CrcByte8(uint8_t crc, uint8_t data) {
        // Fold next byte into CRC
        return pgm_read_byte(&crcTable8[crc ^ data]);
}


uint8_t CrcData8(uint8_t crc, const void* data, uint16_t size) {
        // Fold bytes into CRC
        const uint8_t* p = data;

        while (size--) {
                crc = pgm_read_byte(&crcTable8[crc ^ (*p++)]);
        };
        return crc;
}

uint16_t CrcByte16(uint16_t crc, uint8_t data) {
        // Fold next byte into CRC
        return (crc << 8) ^ pgm_read_word(&crcTable16[(crc >> 8) ^ data]);
}


uint16_t CrcData16(uint16_t crc, const void* data, uint16_t size) {
        // Fold bytes into CRC
        const uint8_t* p = data;

        while (size--) {
                crc = (crc << 8) ^ pgm_read_word(&crcTable16[(crc >> 8) ^ 
(*p++)]);
        };
        return crc;
}




// Implemented with nibbles

static const uint8_t PROGMEM crcTable8n[16] = {
        0x00, 0x8D, 0x97, 0x1A, 0xA3, 0x2E, 0x34, 0xB9,
        0xCB, 0x46, 0x5C, 0xD1, 0x68, 0xE5, 0xFF, 0x72
};

static const uint16_t PROGMEM crcTable16n[16] = {
        0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
        0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022
};


uint8_t CrcByte8n(uint8_t crc, uint8_t data) {
        // Fold next byte into CRC
crc = (crc << 4) ^ (pgm_read_byte(&crcTable8n[(crc >> 4) ^ (data >> 4)])); crc = (crc << 4) ^ (pgm_read_byte(&crcTable8n[(crc >> 4) ^ (data & 0x0f)]));

        return crc;
}

uint8_t CrcData8n(uint8_t crc, const void* data, uint16_t size) {
        // Fold bytes into CRC
        const uint8_t* p = data;

        while (size--) {
crc = (crc << 4) ^ (pgm_read_byte(&crcTable8n[(crc >> 4) ^ ((*p) >> 4)])); crc = (crc << 4) ^ (pgm_read_byte(&crcTable8n[(crc >> 4) ^ ((*p) & 0x0f)]));

                p++;
        };
        return crc;
}

uint16_t CrcByte16n(uint16_t crc, uint8_t data) {
        // Fold next byte into CRC
crc = (crc << 4) ^ (pgm_read_word(&crcTable16n[(crc >> 12) ^ (data >> 4)])); crc = (crc << 4) ^ (pgm_read_word(&crcTable16n[(crc >> 12) ^ (data & 0x0f)]));

        return crc;
}

uint16_t CrcData16n(uint16_t crc, const void* data, uint16_t size) {
        // Fold bytes into CRC
        const uint8_t* p = data;

        while (size--) {
crc = (crc << 4) ^ (pgm_read_word(&crcTable16n[(crc >> 12) ^ ((*p) >> 4)])); crc = (crc << 4) ^ (pgm_read_word(&crcTable16n[(crc >> 12) ^ ((*p) & 0x0f)]));

                p++;
        };
        return crc;
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]