Last active
May 6, 2022 07:18
-
-
Save rcls/627ea2cb60e3136da22539be2aad54d7 to your computer and use it in GitHub Desktop.
LTC6811pec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a 15 bit CRC used by the LTC6811. | |
// | |
// The CRC modulus polynomial is x¹⁵ + x¹⁴ + x¹⁰ + x⁸ + x⁷ + x⁴ + x³ + 1. | |
// | |
// I.e., 0xc599 or 0x4599 depending on whether you include the leading | |
// coefficient. | |
// | |
// Natural bit order is used (high bit of first byte has highest order; for SPI, | |
// first bit on the wire has highest order), both for the data and PEC. | |
// | |
// There is an initialization vector 000000000010000 = 0x10, and a trailer of 15 | |
// zeros (in the datasheet, implicit in the way new bits are stired in - the | |
// algorithm there does the reduction of the data polynomial multiplied by x¹⁵. | |
// | |
// The PEC is appended to the data and padded to 16 bits by appending | |
// a final zero. | |
// | |
// So the concatenation: 0x0010, data, PEC15 (with or without the final 0 bit) | |
// should be a polynomial multiple of the CRC modulus. | |
// | |
// In our calculations, we keep the CRC aligned in the high 15 bits of a 16 bit | |
// word, as this matches the output format. | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#define POLY 0xc599 | |
// Left shift AKA multiplication by X, modulo the polynomial. | |
#define SHL(x) ((x & 0x8000 ? x ^ POLY : x) << 1) | |
// CRC of a single byte with one bit in the numbered position (0x01 -> B0, | |
// 0x80 -> B7). | |
enum { | |
B0 = SHL(0x8000), B1 = SHL(B0), B2 = SHL(B1), B3 = SHL(B2), | |
B4 = SHL(B3), B5 = SHL(B4), B6 = SHL(B5), B7 = SHL(B6), | |
}; | |
#define A(X) X, X^B0, X^B1, X^B1^B0, X^B2, X^B2^B0, X^B2^B1, X^B2^B1^B0, | |
#define B(X) A(X) A(X^B3) A(X^B4) A(X^B4^B3) | |
static uint16_t crc_table[256] = { | |
B(0) B(B5) B(B6) B(B6^B5) B(B7) B(B7^B5) B(B7^B6) B(B7^B6^B5) | |
}; | |
static inline uint16_t crc_byte(uint16_t c, int byte) | |
{ | |
return c << 8 ^ crc_table[byte ^ c >> 8]; | |
} | |
static uint16_t crc_bytes(uint16_t c, const uint8_t * buf, size_t len) | |
{ | |
for (size_t i = 0; i < len; ++i) | |
c = crc_byte(c, buf[i]); | |
return c; | |
} | |
static inline int ltc6811_pec(const uint8_t * buf, size_t len) | |
{ | |
// Note the left shift by one on the initialization value to match our | |
// high-bit aligned format. | |
return crc_bytes(0x0020, buf, len); | |
} | |
static inline bool ltc6811_check(const uint8_t * buf, size_t len) | |
{ | |
return len >= 2 && ltc6811_pec(buf, len) == 0 && ~buf[len - 1] & 1; | |
} | |
int main() | |
{ | |
const uint8_t bytes[] = { 0, 1 }; | |
int c = ltc6811_pec(bytes, sizeof bytes); | |
printf("%04x (expect 0x3D6E)\n", c); | |
const uint8_t check[] = { 0, 1, 0x3d, 0x6e }; | |
printf("Check = %s\n", | |
ltc6811_check(check, sizeof check) ? "PASS" : "FAIL"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment