如何提高CRC-5计算的时间效率?
How to improve time efficiency of CRC-5 calculation?
刚刚开始研究CRC以及如何在软件中实现它。我的信息来源主要是关注document. Here is mentioned some simple algorithm for calculating CRC for any generator polynomial. I have attempted to write this algorithm in C++ language. I have tested it for generator polynomial x^5 + x^4 + x^2 + 1 (CRC-5) (generator polynomial used by chip) with usage of this online calculator 并且有效
#include <iostream>
using namespace std;
int main() {
uint8_t data_byte = 0x31;
// polynom x^5 + x^4 + x^2 + 1
uint16_t polynom = 0x35;
// register contains 0 at the beginning
uint32_t crc = 0;
uint32_t message = 0;
// shift the message byte to left by so many bits which is needed for generator polynomial
message = (data_byte << 5);
// now the message byte is 13 bits long
uint8_t processed_bit = 13;
while(processed_bit > 0) {
// prepare free space for new bit from the message byte
crc = crc << 1;
// find out value of current msb in the message byte
message = message << 1;
if(message & 0x2000) {
// msb in message byte is "1"
// lsb in register is set to "1"
crc |= 1U;
} else {
// msb in message byte is "0"
// lsb in register is set to "0"
crc &= ~1U;
}
// remove msb from message byte
message = message & ~0x2000;
if(crc & 0x20) {
// subtract current multiple of the generator polynomial
crc = crc ^ polynom;
}
// remove msb from the register
crc = crc & ~0x20;
processed_bit--;
}
cout << "CRC: " << (int)crc << endl;
return 0;
}
很明显,这个程序在执行时间上是无效的。所以我一直在思考一个可能性,如何从这个角度去改进它。我知道有一个变体可以使用包含预先计算的提醒的查找 table,但我想避免使用这种方法。有人知道如何从执行时间的角度改进上述算法吗?提前感谢您的任何建议。
快速浏览一下就会发现一些不必要的语句。您不需要 crc &= ~1U;
,因为 crc = crc << 1;
已经在那里放了一个零。您不需要 message = message & ~0x2000;
,因为您只会查看其中的一位。只需让其他位向上移动即可。您不需要 crc = crc & ~0x20;
,因为异或多项式已经做到了。
如果您阅读链接的文档,您会发现您不需要再处理五位(总共 13 位)。您只需要处理八个消息位。同样阅读该文档,您不需要一次一个地输入消息位。可以将报文字节直接异或到CRC寄存器,然后把寄存器中的8位全部处理。
最后,您可以通过 table 查找显着加快计算速度,一次处理八位而不是一次一位。您链接的文档中也对此进行了精美描述。你可以找到code here自动生成table和C代码来计算。
最后,如果您没有计算正确的事情,那么 none 这很重要。您需要先用芯片的数据验证计算。我找到了this document with details on the CRC calculation for that chip。您需要花一些时间了解它并详细了解它。
为了直接回答您的问题,这里有一些代码可以完成您的代码的功能,但要简单得多。它也被扩展到 n 位,而不仅仅是八位。它执行 n 循环而不是 n+5 循环:
// Return a CRC-5 of the low n bits of data. The remaining bits of data must be
// zero. n must be in [5..32].
uint8_t crc5(uint32_t data, int n) {
int shift = n - 5;
uint32_t poly = (uint32_t)0x15 << shift;
uint32_t top = (uint32_t)1 << (n - 1);
do {
data = data & top ? (data << 1) ^ poly : data << 1;
} while (--n);
return (data >> shift) & 0x1f;
}
更简单和更快的仍然是你的限制为八位,展开:
uint8_t crc5_8(uint8_t data) {
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
return data >> 3;
}
但是两者都无法计算出您的芯片需要什么。
刚刚开始研究CRC以及如何在软件中实现它。我的信息来源主要是关注document. Here is mentioned some simple algorithm for calculating CRC for any generator polynomial. I have attempted to write this algorithm in C++ language. I have tested it for generator polynomial x^5 + x^4 + x^2 + 1 (CRC-5) (generator polynomial used by chip) with usage of this online calculator 并且有效
#include <iostream>
using namespace std;
int main() {
uint8_t data_byte = 0x31;
// polynom x^5 + x^4 + x^2 + 1
uint16_t polynom = 0x35;
// register contains 0 at the beginning
uint32_t crc = 0;
uint32_t message = 0;
// shift the message byte to left by so many bits which is needed for generator polynomial
message = (data_byte << 5);
// now the message byte is 13 bits long
uint8_t processed_bit = 13;
while(processed_bit > 0) {
// prepare free space for new bit from the message byte
crc = crc << 1;
// find out value of current msb in the message byte
message = message << 1;
if(message & 0x2000) {
// msb in message byte is "1"
// lsb in register is set to "1"
crc |= 1U;
} else {
// msb in message byte is "0"
// lsb in register is set to "0"
crc &= ~1U;
}
// remove msb from message byte
message = message & ~0x2000;
if(crc & 0x20) {
// subtract current multiple of the generator polynomial
crc = crc ^ polynom;
}
// remove msb from the register
crc = crc & ~0x20;
processed_bit--;
}
cout << "CRC: " << (int)crc << endl;
return 0;
}
很明显,这个程序在执行时间上是无效的。所以我一直在思考一个可能性,如何从这个角度去改进它。我知道有一个变体可以使用包含预先计算的提醒的查找 table,但我想避免使用这种方法。有人知道如何从执行时间的角度改进上述算法吗?提前感谢您的任何建议。
快速浏览一下就会发现一些不必要的语句。您不需要 crc &= ~1U;
,因为 crc = crc << 1;
已经在那里放了一个零。您不需要 message = message & ~0x2000;
,因为您只会查看其中的一位。只需让其他位向上移动即可。您不需要 crc = crc & ~0x20;
,因为异或多项式已经做到了。
如果您阅读链接的文档,您会发现您不需要再处理五位(总共 13 位)。您只需要处理八个消息位。同样阅读该文档,您不需要一次一个地输入消息位。可以将报文字节直接异或到CRC寄存器,然后把寄存器中的8位全部处理。
最后,您可以通过 table 查找显着加快计算速度,一次处理八位而不是一次一位。您链接的文档中也对此进行了精美描述。你可以找到code here自动生成table和C代码来计算。
最后,如果您没有计算正确的事情,那么 none 这很重要。您需要先用芯片的数据验证计算。我找到了this document with details on the CRC calculation for that chip。您需要花一些时间了解它并详细了解它。
为了直接回答您的问题,这里有一些代码可以完成您的代码的功能,但要简单得多。它也被扩展到 n 位,而不仅仅是八位。它执行 n 循环而不是 n+5 循环:
// Return a CRC-5 of the low n bits of data. The remaining bits of data must be
// zero. n must be in [5..32].
uint8_t crc5(uint32_t data, int n) {
int shift = n - 5;
uint32_t poly = (uint32_t)0x15 << shift;
uint32_t top = (uint32_t)1 << (n - 1);
do {
data = data & top ? (data << 1) ^ poly : data << 1;
} while (--n);
return (data >> shift) & 0x1f;
}
更简单和更快的仍然是你的限制为八位,展开:
uint8_t crc5_8(uint8_t data) {
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
return data >> 3;
}
但是两者都无法计算出您的芯片需要什么。