Skip to content

Latest commit

 

History

History
180 lines (160 loc) · 8.62 KB

README.md

File metadata and controls

180 lines (160 loc) · 8.62 KB

mp-crc

This is an accelerated table-based crc library for micropython that implements a variety of crc variants from 8 to 64 bits. Crc variants may be added by uncommenting or adding their definitions in crc/init.py or be defined in a dict (see below).

At present these definitions are active:

class Crc8:
    # Name      (Width, Poly, Init, RefIn, RefOut, Xorout, Check)
    crc7ls    = (8,     0x12, 0x00, False, False,  0x00,   0xea)
    crc8      = (8,     0x07, 0x00, False, False,  0x00,   0xf4)
    ccitt     = crc8
    saej1850  = (8,     0x1d, 0x00, False, False,  0x00,   0x37)
    autosar   = (8,     0x2f, 0xff, False, False,  0xff,   0xdf)
    bluetooth = (8,     0xa7, 0x00, True,  True,   0x00,   0x26)
    maxim_dow = (8,     0x31, 0x00, True,  True,   0x00,   0xa1)
#     cdma2000  = (8,     0x9b, 0xff, False, False,  0x00,   0xda)
#     darc      = (8,     0x39, 0x00, True,  True,   0x00,   0x15)
#     dvb_s2    = (8,     0xd5, 0x00, False, False,  0x00,   0xbc)
#     ebu       = (8,     0x1d, 0xff, True,  True,   0x00,   0x97)
#     i_code    = (8,     0x1d, 0xfd, False, False,  0x00,   0x7e)
#     itu       = (8,     0x07, 0x00, False, False,  0x55,   0xa1)
#     rohc      = (8,     0x07, 0xff, True,  True,   0x00,   0xd0)
#     wcdma     = (8,     0x9b, 0x00, True,  True,   0x00,   0x25)

class Crc16:
    # Name      (Width,  Poly,   Init,   RefIn, RefOut, Xorout, Check)
    xmodem    = (16,    0x1021, 0x0000, False, False,  0x0000, 0x31c3)
    usb       = (16,    0x8005, 0xffff, True,  True,   0xffff, 0xb4c8)
    ccitt     = xmodem
    gsm       = (16,    0x1021, 0x0000, False, False,  0xffff, 0xce3c)
    profibus  = (16,    0x1dcf, 0xffff, False, False,  0xffff, 0xa819)
    modbus    = (16,    0x8005, 0xffff, True,  True,   0x0000, 0x4b37)
#     arc       = (16,    0x8005, 0x0000, True,  True,   0x0000, 0xbb3d),
#     buypass   = (16,    0x8005, 0x0000, False, False,  0x0000, 0xfee8),
#     dds_110   = (16,    0x8005, 0x800d, False, False,  0x0000, 0x9ecf),
#     maxim     = (16,    0x8005, 0x0000, True,  True,   0xffff, 0x44c2),
#     aug_ccitt = (16,    0x1021, 0x1d0f, False, False,  0x0000, 0xe5cc),
#     ccitt_false=(16,    0x1021, 0xffff, False, False,  0x0000, 0x29b1),
#     genibus   = (16,    0x1021, 0xffff, False, False,  0xffff, 0xd64e),
#     kermit    = (16,    0x1021, 0x0000, True,  True,   0x0000, 0x2189),
#     mcrf4xx   = (16,    0x1021, 0xffff, True,  True,   0x0000, 0x6f91),
#     riello    = (16,    0x1021, 0xb2aa, True,  True,   0x0000, 0x63d0),
#     tms37157  = (16,    0x1021, 0x89ec, True,  True,   0x0000, 0x26b1),
#     x_25        (16,    0x1021, 0xffff, True,  True,   0xffff, 0x906e),
#     a           (16,    0x1021, 0xc6c6, True,  True,   0x0000, 0xbf05)
#     cdma2000  = (16,    0xc867, 0xffff, False, False,  0x0000, 0x4c06),
#     dect_r    = (16,    0x0589, 0x0000, False, False,  0x0001, 0x007e),
#     dect_x    = (16,    0x0589, 0x0000, False, False,  0x0000, 0x007f),
#     dnp       = (16,    0x3d65, 0x0000, True,  True,   0xffff, 0xea82),
#     en_13757  = (16,    0x3d65, 0x0000, False, False,  0xffff, 0xc2b7),
#     t10-dif   = (16,    0x8bb7, 0x0000, False, False,  0x0000, 0xd0db),
#     teledisk  = (16,    0xa097, 0x0000, False, False,  0x0000, 0x0fb3),

class Crc32:
    # Name     (Width,  Poly,       Init,       RefIn, RefOut, Xorout,     Check)
    crc32      = (32,    0x04c11db7, 0xffffffff, True,  True,   0xffffffff, 0xcbf43926)
    autosar    = (32,    0xf4acfb13, 0xffffffff, True,  True,   0xffffffff, 0x1697d06a)
    bzip2      = (32,    0x04c11db7, 0xffffffff, False, False,  0xffffffff, 0xfc891918)
    posix      = (32,    0x04c11db7, 0x00000000, False, False,  0xffffffff, 0x765e7680)
    sata       = (32,    0x04c11db7, 0x52325032, False, False,  0x00000000, 0xcf72afe8)
#     jamcrc     = (32,    0x04c11db7, 0xffffffff, True,  True,   0x00000000, 0x340bc6d9)
#     mpeg-2     = (32,    0x04c11db7, 0xffffffff, False, False,  0x00000000, 0x0376e6e7)
#     xfer       = (32,    0x000000af, 0x00000000, False, False,  0x00000000, 0xbd0be338)
#     c          = (32,    0x1edc6f41, 0xffffffff, True,  True,   0xffffffff, 0xe3069283)
#     d          = (32,    0xa833982b, 0xffffffff, True,  True,   0xffffffff, 0x87315576)
#     q          = (32,    0x814141ab, 0x00000000, False, False,  0x00000000, 0x3010bf7f)
    
class Crc64:
    # Name   (Width,  Poly,           Init,                RefIn, RefOut, Xorout,             Check)
    crc64   = (64, 0x42f0e1eba9ea3693, 0x0000000000000000, False, False,  0x0000000000000000, 0x6c40df5f0b497347)
    ecma_182 = crc64
    go_iso  = (64, 0x000000000000001b, 0xffffffffffffffff, True,  True,   0xffffffffffffffff, 0xb90956c775a41001)
#     we      = (64, 0x42f0e1eba9ea3693, 0xffffffffffffffff, False, False,  0xffffffffffffffff, 0x62ec59e3f1a4f00a)
#     xz      = (64, 0x42f0e1eba9ea3693, 0xffffffffffffffff, True,  True,   0xffffffffffffffff, 0x995dc9bbdf1939fa)

Implementations of the crc calculations are available as ordinary MP (interpreted bytecode), native, viper, asm_xtensa or asm_thumb.

For using a certain crc variant (e.g. crc16 ccitt) and acceleration (e.g. asm_thumb) you import like:

from crc import Calculator, Crc16, Opt_asm_thumb

Which imports the main Calculator class, the Crc16 definitions (which include ccitt) and (optionally) the optimized asm_thumb implementation.

Then you create the actual calculator (which includes a computation of the look-up table) by:

calculator = Calculator(Crc16.ccitt)

You may then use it to calculate and return the crc with e.g.:

data = bytes('123456789', 'utf-8')
print('Crc16.ccitt:', hex(calculator.checksum(data)))

Often you do not want to return the crc computation result directly but digest a lot of data first. For that there is a .digest() member function:

data1 = bytes('123', 'utf-8')
data2 = bytes('456789', 'utf-8')

calculator.digest(data1)
calculator.digest(data2)                         # We may digest first and then do a checksum.
print('Crc16.usb:', hex(calculator.checksum())

Note that the .checksum() member function also does a reset of the internal crc computation state.

Crc definition may be defined on-the-fly like:

config = {'width': 16,
          'poly':  0x1021,
          'init':  0x0000,
          'refin': False,
          'refout':False,
          'xorout':0xffff,
          'check': 0xce3c  # this is optional, may comment it out
          }
calculator = Calculator(config)

The file examples.pycontains more usage examples. I recommend studying it. The file check.py contains a checksum test for the present crc definitions. The file bench.py does a benchmark of the crc computations.

Example benchmark results:

Blackpill STM32F411 @ 96MHz

Crc implementation: bytecode
crc8: 0x0c,   9.02µs per byte
crc8: 0x0c,   9.02µs per byte
crc8: 0x0c,   9.02µs per byte
crc16: 0x3359,  12.65µs per byte
crc16: 0x3359,  12.65µs per byte
crc16: 0x3359,  12.65µs per byte
crc32: 0xd6bbe339,  72.72µs per byte
crc32: 0xd6bbe339,  72.89µs per byte
crc32: 0xd6bbe339,  72.88µs per byte
crc64: 0xcca94235057ad7ea,  76.10µs per byte
crc64: 0xcca94235057ad7ea,  76.36µs per byte
crc64: 0xcca94235057ad7ea,  76.27µs per byte

Crc implementation: viper
crc8: 0x0c,   0.46µs per byte
crc8: 0x0c,   0.46µs per byte
crc8: 0x0c,   0.46µs per byte
crc16: 0x3359,   0.63µs per byte
crc16: 0x3359,   0.63µs per byte
crc16: 0x3359,   0.63µs per byte
crc32: 0xd6bbe339,   0.68µs per byte
crc32: 0xd6bbe339,   0.67µs per byte
crc32: 0xd6bbe339,   0.67µs per byte
crc64: 0xcca94235057ad7ea,   1.33µs per byte
crc64: 0xcca94235057ad7ea,   1.32µs per byte
crc64: 0xcca94235057ad7ea,   1.32µs per byte

Crc implementation: asm_thumb
crc8: 0x0c,   0.13µs per byte
crc8: 0x0c,   0.13µs per byte
crc8: 0x0c,   0.13µs per byte
crc16: 0x3359,   0.18µs per byte
crc16: 0x3359,   0.17µs per byte
crc16: 0x3359,   0.18µs per byte
crc32: 0xd6bbe339,   0.20µs per byte
crc32: 0xd6bbe339,   0.19µs per byte
crc32: 0xd6bbe339,   0.19µs per byte
crc64: 0xcca94235057ad7ea,   0.26µs per byte
crc64: 0xcca94235057ad7ea,   0.26µs per byte
crc64: 0xcca94235057ad7ea,   0.26µs per byte

The file Opt_asm_xtensa.py is an example of using the @micropython.asm_xtensa decorator. Which seems to be only a partial implementation. The limitations may be overcome by using the data()statement. I created preliminary docs for it and presented them here. Using it enables fast calculations for the esp8266 architecture. Unfortunately for the esp32 the @micropython.asm_xtensawin decorator would be needed, which is not available. So you are limited to viper if you want to do fast calculations (without resorting to C) on esp32.