I've written a CRC calculator to match one implemented in an electronic control module. The ultimate purpose is for downloading large amounts of data into the module.

First draft: CRC the whole file and download the whole file to the module. This works just fine, CRC-wise. However, the data is sparse, so takes much longer than truely needed to download.

Second draft: Partion file into 32 byte blocks; CRC and download only the blocks with actual data. The data downloads fine, but the CRC check is "off by one".

That is to say that when the CRC checker in the module performs the check on the data blocks received, the final "total" CRC value is 0xFFFF. It should be 0x0000.

Note that this error only occures when my CRC generator is run on a block-by-block basis, rather than the whole file all at once:

@data = read_data($infile); # @data is global $data[0x6FFE] = 0; # zero CRC $data[0x6FFF = 0; # locations $crc = crc16(0x0000, 0x6FFF, 0); # works $crc = 0; for ($a = 0x0000; $a < 0x6fff; $a += 32) { # final value next if (unusedBlock($a, 32); # off by one $crc = crc16($a, $a + 32, $crc); } $data[0x6FFE] = $crc >> 8; # save $data[0x6FFF] = $crc & 0xFF; # CRC write_data($outfile); # or write_data_blocks($outfile);

Obviously, the block-by-block CRC is based on fewer bytes than the full CRC, so is, as expected, different.

The module software is designed handle the data download in blocks, and, therefore, runs it CRC calculation block-by-block. In fact, even when the whole file is downloaded, it is still blocked. The difference is that all blocks are sent for the whole file, while only a subset for block-by-block.

Below are my Perl CRC routine (called by the above code) and the C source of the module's CRC routine.

sub crc16 ($$$) { my ($startadr, $endadr, $crc) = @_; my ($cadr, $adr, $i, $u, $d); for ($adr = $startadr; $adr <= $endadr; $adr++) { if (defined($data[$adr])) { $d = $data[$adr] & 0xFF; } else { $d = 0xFF; } $i = $crc >> 8; $crc <<= 8; $crc &= 0xFFFF; $crc |= $d; $crc ^= $crctable[$i]; } return $crc; }
void VerifyFlashBlock(UINT8 len, UINT16 address) { UINT8 byte_value; UINT8 crc_table_index; for (;len > 0; len--) { byte_value = _READ_BYTE_FROM_FLASH(address); crc_table_index = crc >> 8; crc = (crc << 8) | byte_value; crc = crc ^ _Crc_table[crc_table_index]; address++; buffer++; } }

In reply to CRC off-by-one by rlw

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.