MAX14900E為高性能、8通道工業(yè)開(kāi)關(guān),具有豐富、先進(jìn)的特性集。SPI接口允許微控制器監(jiān)視和控制MAX14900E的大部分方面。為了增強(qiáng)魯棒性,MAX14900E中的硬件CRC(循環(huán)冗余校驗(yàn))電路可以選擇保護(hù)其與微處理器之間的所有數(shù)據(jù),防止誤碼。
然而,在MAX14900E中啟用CRC功能是不夠的。微處理器還必須在軟件中實(shí)現(xiàn)相同的CRC算法,既要為發(fā)送到MAX14900E的數(shù)據(jù)附加校驗(yàn)位,又要驗(yàn)證從MAX<>E接收的數(shù)據(jù)。實(shí)現(xiàn)此目的的一種方法是檢查數(shù)據(jù)手冊(cè),并使用它來(lái)創(chuàng)建自定義固件以實(shí)現(xiàn)必要的CRC功能。
更好的方法是改用本應(yīng)用筆記中的功能。這些是用C語(yǔ)言編寫的,應(yīng)該很容易移植到大多數(shù)常見(jiàn)的微處理器上。
選擇正確的來(lái)源
本應(yīng)用筆記提供了六組C源代碼,每組都實(shí)現(xiàn)一個(gè)CRC生成器和一個(gè)CRC檢查器。MAX14900E使用單字節(jié)或雙字節(jié)包與微處理器通信。其中三個(gè)代碼集實(shí)現(xiàn)單字節(jié)數(shù)據(jù)包的生成器和檢查器算法,而其他三個(gè)代碼集實(shí)現(xiàn)雙字節(jié)數(shù)據(jù)包的生成器和檢查器算法。
除了選擇單字節(jié)或雙字節(jié)數(shù)據(jù)包與MAX14900E通信外,另一個(gè)選擇標(biāo)準(zhǔn)是代碼大小與執(zhí)行速度的重要性。本應(yīng)用筆記提供了三種不同假設(shè)的源代碼。首先,小代碼大小是最重要的(執(zhí)行速度是次要的)。其次,執(zhí)行速度比代碼大小更重要。第三,在代碼大小和執(zhí)行速度之間取得平衡。奇怪的是,在某些微處理器架構(gòu)中,第三個(gè)“折衷”選項(xiàng)與第二個(gè)選項(xiàng)一樣快,其中表查找相對(duì)昂貴。
使用的 API 約定
每個(gè)代碼集定義兩個(gè)函數(shù)調(diào)用,一個(gè)用于 CRC 生成器,另一個(gè)用于 CRC 檢查器。請(qǐng)注意,在這些代碼示例中,“無(wú)符號(hào)字符”是 8 位無(wú)符號(hào)值的別名,有時(shí)以不同的方式標(biāo)記,例如 UINT8。函數(shù)返回值為“無(wú)符號(hào)字符”或“布爾值”,但如果返回值為“int”,而不是該微處理器的本機(jī)存儲(chǔ)大小,則某些微處理器執(zhí)行代碼的速度更快。
單字節(jié)生成器函數(shù)調(diào)用如下所示:
send2 = generator (send1);
Send1是發(fā)送到MAX14900E的字節(jié)。代碼應(yīng)先發(fā)送1,后再發(fā)送2至MAX14900E。同樣,雙字節(jié)生成器函數(shù)調(diào)用如下所示:
send3 = generator(send1, send2);
用戶應(yīng)通過(guò)SPI接口發(fā)送3個(gè)字節(jié),先發(fā)送1,后跟send2,然后發(fā)送3。
微處理器通過(guò)SPI接口將配置設(shè)置發(fā)送到MAX14900E,MAX14900E同時(shí)將狀態(tài)信息返回給微處理器。單字節(jié)檢查器如下所示:
flag = checker (ret1, ret2);
如果返回字節(jié)和 CRC 匹配,則布爾“標(biāo)志”為真 (!= 0)。雙字節(jié)檢查器如下所示:
flag = checker (ret1, ret2, ret3);
小代碼大小
本節(jié)中的代碼示例使用循環(huán)來(lái)構(gòu)建 CRC,一次生成一位。出于這個(gè)原因,它們不是那么快,而是緊湊地編譯。這些代碼片段依賴于幫助程序例程(Loop_CRC)來(lái)執(zhí)行實(shí)際的一次位 CRC 計(jì)算。
unsigned char Loop_CRC (unsigned char crc, unsigned char byte) { int i; for (i = 0; i < 8; i++) { crc <<= 1; if (crc & 0x80) crc ^= 0xB7; // 0x37 with MSBit on purpose if (byte & 0x80) crc ^=1; byte <<= 1; } return crc; } // unsigned char crcSmallEncode8 (unsigned char byte1) { unsigned char synd; synd = Loop_CRC (0x7f, byte1); return Loop_CRC (synd, 0x80) | 0x80; } // bool crcSmallCheck8 (unsigned char byte1, unsigned char byte2) { unsigned char synd; synd = Loop_CRC (0x7f, byte1); return Loop_CRC (synd, byte2) == 0; } unsigned char Loop_CRC (unsigned char crc, unsigned char byte) { int i; for (i = 0; i < 8; i++) { crc <<= 1; if (crc & 0x80) crc ^= 0xB7; // 0x37 with MSBit on purpose if (byte & 0x80) crc ^=1; byte <<= 1; } return crc; } // unsigned char crcSmallEncode16 (unsigned char byte1, unsigned char byte2) { unsigned char synd; synd = Loop_CRC (0x7f, byte1); synd = Loop_CRC (synd, byte2); return Loop_CRC (synd, 0x80) | 0x80; } // bool crcSmallCheck16 (unsigned char byte1, unsigned char byte2, unsigned char byte3) { unsigned char synd; synd = Loop_CRC (0x7f, byte1); synd = Loop_CRC (synd, byte2); return Loop_CRC (synd, byte3) == 0; }
快速執(zhí)行
本節(jié)中的代碼示例以代碼大小換取速度。兩個(gè) 128 字節(jié)的表對(duì)每個(gè)表訪問(wèn)的一個(gè)完整字節(jié)的數(shù)據(jù)進(jìn)行編碼。注意,如果用戶只想保護(hù)發(fā)送到MAX14900E的數(shù)據(jù),并且使用單字節(jié)事務(wù),則用戶只需要第二個(gè)表。
// const unsigned char propagate8_next0 [128] = { 0x00, 0x6E, 0x6B, 0x05, 0x61, 0x0F, 0x0A, 0x64, 0x75, 0x1B, 0x1E, 0x70, 0x14, 0x7A, 0x7F, 0x11, 0x5D, 0x33, 0x36, 0x58, 0x3C, 0x52, 0x57, 0x39, 0x28, 0x46, 0x43, 0x2D, 0x49, 0x27, 0x22, 0x4C, 0x0D, 0x63, 0x66, 0x08, 0x6C, 0x02, 0x07, 0x69, 0x78, 0x16, 0x13, 0x7D, 0x19, 0x77, 0x72, 0x1C, 0x50, 0x3E, 0x3B, 0x55, 0x31, 0x5F, 0x5A, 0x34, 0x25, 0x4B, 0x4E, 0x20, 0x44, 0x2A, 0x2F, 0x41, 0x1A, 0x74, 0x71, 0x1F, 0x7B, 0x15, 0x10, 0x7E, 0x6F, 0x01, 0x04, 0x6A, 0x0E, 0x60, 0x65, 0x0B, 0x47, 0x29, 0x2C, 0x42, 0x26, 0x48, 0x4D, 0x23, 0x32, 0x5C, 0x59, 0x37, 0x53, 0x3D, 0x38, 0x56, 0x17, 0x79, 0x7C, 0x12, 0x76, 0x18, 0x1D, 0x73, 0x62, 0x0C, 0x09, 0x67, 0x03, 0x6D, 0x68, 0x06, 0x4A, 0x24, 0x21, 0x4F, 0x2B, 0x45, 0x40, 0x2E, 0x3F, 0x51, 0x54, 0x3A, 0x5E, 0x30, 0x35, 0x5B }; const unsigned char propagate8_next1 [128] = { 0xB7, 0xD9, 0xDC, 0xB2, 0xD6, 0xB8, 0xBD, 0xD3, 0xC2, 0xAC, 0xA9, 0xC7, 0xA3, 0xCD, 0xC8, 0xA6, 0xEA, 0x84, 0x81, 0xEF, 0x8B, 0xE5, 0xE0, 0x8E, 0x9F, 0xF1, 0xF4, 0x9A, 0xFE, 0x90, 0x95, 0xFB, 0xBA, 0xD4, 0xD1, 0xBF, 0xDB, 0xB5, 0xB0, 0xDE, 0xCF, 0xA1, 0xA4, 0xCA, 0xAE, 0xC0, 0xC5, 0xAB, 0xE7, 0x89, 0x8C, 0xE2, 0x86, 0xE8, 0xED, 0x83, 0x92, 0xFC, 0xF9, 0x97, 0xF3, 0x9D, 0x98, 0xF6, 0xAD, 0xC3, 0xC6, 0xA8, 0xCC, 0xA2, 0xA7, 0xC9, 0xD8, 0xB6, 0xB3, 0xDD, 0xB9, 0xD7, 0xD2, 0xBC, 0xF0, 0x9E, 0x9B, 0xF5, 0x91, 0xFF, 0xFA, 0x94, 0x85, 0xEB, 0xEE, 0x80, 0xE4, 0x8A, 0x8F, 0xE1, 0xA0, 0xCE, 0xCB, 0xA5, 0xC1, 0xAF, 0xAA, 0xC4, 0xD5, 0xBB, 0xBE, 0xD0, 0xB4, 0xDA, 0xDF, 0xB1, 0xFD, 0x93, 0x96, 0xF8, 0x9C, 0xF2, 0xF7, 0x99, 0x88, 0xE6, 0xE3, 0x8D, 0xE9, 0x87, 0x82, 0xEC }; // unsigned char crcFastEncode8 (unsigned char byte1) { unsigned char synd; synd = (byte1 & 0x80) ? 0xEC : 0x5B; // 6C & 5B before optimization synd ^= byte1; return propagate8_next1[synd]; } bool crcFastCheck8 (unsigned char byte1, unsigned char byte2) { unsigned char synd; unsigned char const *ptr; synd = (byte1 & 0x80) ? 0xEC : 0x5B; synd ^= byte1; ptr = byte2 & 0x80 ? propagate8_next1 : propagate8_next0; return (ptr[synd] ^ byte2) == 0; } // const unsigned char propagate8_next0 [128] = { 0x00, 0x6E, 0x6B, 0x05, 0x61, 0x0F, 0x0A, 0x64, 0x75, 0x1B, 0x1E, 0x70, 0x14, 0x7A, 0x7F, 0x11, 0x5D, 0x33, 0x36, 0x58, 0x3C, 0x52, 0x57, 0x39, 0x28, 0x46, 0x43, 0x2D, 0x49, 0x27, 0x22, 0x4C, 0x0D, 0x63, 0x66, 0x08, 0x6C, 0x02, 0x07, 0x69, 0x78, 0x16, 0x13, 0x7D, 0x19, 0x77, 0x72, 0x1C, 0x50, 0x3E, 0x3B, 0x55, 0x31, 0x5F, 0x5A, 0x34, 0x25, 0x4B, 0x4E, 0x20, 0x44, 0x2A, 0x2F, 0x41, 0x1A, 0x74, 0x71, 0x1F, 0x7B, 0x15, 0x10, 0x7E, 0x6F, 0x01, 0x04, 0x6A, 0x0E, 0x60, 0x65, 0x0B, 0x47, 0x29, 0x2C, 0x42, 0x26, 0x48, 0x4D, 0x23, 0x32, 0x5C, 0x59, 0x37, 0x53, 0x3D, 0x38, 0x56, 0x17, 0x79, 0x7C, 0x12, 0x76, 0x18, 0x1D, 0x73, 0x62, 0x0C, 0x09, 0x67, 0x03, 0x6D, 0x68, 0x06, 0x4A, 0x24, 0x21, 0x4F, 0x2B, 0x45, 0x40, 0x2E, 0x3F, 0x51, 0x54, 0x3A, 0x5E, 0x30, 0x35, 0x5B }; const unsigned char propagate8_next1 [128] = { 0xB7, 0xD9, 0xDC, 0xB2, 0xD6, 0xB8, 0xBD, 0xD3, 0xC2, 0xAC, 0xA9, 0xC7, 0xA3, 0xCD, 0xC8, 0xA6, 0xEA, 0x84, 0x81, 0xEF, 0x8B, 0xE5, 0xE0, 0x8E, 0x9F, 0xF1, 0xF4, 0x9A, 0xFE, 0x90, 0x95, 0xFB, 0xBA, 0xD4, 0xD1, 0xBF, 0xDB, 0xB5, 0xB0, 0xDE, 0xCF, 0xA1, 0xA4, 0xCA, 0xAE, 0xC0, 0xC5, 0xAB, 0xE7, 0x89, 0x8C, 0xE2, 0x86, 0xE8, 0xED, 0x83, 0x92, 0xFC, 0xF9, 0x97, 0xF3, 0x9D, 0x98, 0xF6, 0xAD, 0xC3, 0xC6, 0xA8, 0xCC, 0xA2, 0xA7, 0xC9, 0xD8, 0xB6, 0xB3, 0xDD, 0xB9, 0xD7, 0xD2, 0xBC, 0xF0, 0x9E, 0x9B, 0xF5, 0x91, 0xFF, 0xFA, 0x94, 0x85, 0xEB, 0xEE, 0x80, 0xE4, 0x8A, 0x8F, 0xE1, 0xA0, 0xCE, 0xCB, 0xA5, 0xC1, 0xAF, 0xAA, 0xC4, 0xD5, 0xBB, 0xBE, 0xD0, 0xB4, 0xDA, 0xDF, 0xB1, 0xFD, 0x93, 0x96, 0xF8, 0x9C, 0xF2, 0xF7, 0x99, 0x88, 0xE6, 0xE3, 0x8D, 0xE9, 0x87, 0x82, 0xEC }; // // This is the fast (one byte at a time) algorithm // // This is so fast that one could benefit from running it in-line // unsigned char crcFastEncode16 (unsigned char byte1, unsigned char byte2) { unsigned char synd; unsigned char const *ptr; synd = (byte1 & 0x80) ? 0xEC : 0x5B; synd ^= byte1; ptr = byte2 & 0x80 ? propagate8_next1 : propagate8_next0; synd = ptr[synd] ^ byte2; return propagate8_next1[synd]; } bool crcFastCheck16 (unsigned char byte1, unsigned char byte2, unsigned char byte3) { unsigned char synd; unsigned char const *ptr; synd = (byte1 & 0x80) ? 0xEC : 0x5B; synd ^= byte1; ptr = byte2 & 0x80 ? propagate8_next1 : propagate8_next0; synd = ptr[synd] ^ byte2; ptr = byte3 & 0x80 ? propagate8_next1 : propagate8_next0; return (ptr[synd] ^ byte3) == 0; }
平衡
本節(jié)中的代碼示例在代碼大小和執(zhí)行速度之間取得了平衡。一個(gè)表查找將 7 位數(shù)據(jù)編碼到 CRC 中。第八位使用大小優(yōu)化代碼中使用的技術(shù)進(jìn)行編碼。一些哈佛架構(gòu)設(shè)備具有相對(duì)昂貴的表查找執(zhí)行時(shí)間,對(duì)于這類微處理器,這種平衡代碼的執(zhí)行速度可能與速度優(yōu)化的代碼一樣快,甚至可能更快。
// unsigned char propagate7 [128] = { 0x00, 0x6E, 0xDC, 0xB2, 0xD6, 0xB8, 0x0A, 0x64, 0xC2, 0xAC, 0x1E, 0x70, 0x14, 0x7A, 0xC8, 0xA6, 0xEA, 0x84, 0x36, 0x58, 0x3C, 0x52, 0xE0, 0x8E, 0x28, 0x46, 0xF4, 0x9A, 0xFE, 0x90, 0x22, 0x4C, 0xBA, 0xD4, 0x66, 0x08, 0x6C, 0x02, 0xB0, 0xDE, 0x78, 0x16, 0xA4, 0xCA, 0xAE, 0xC0, 0x72, 0x1C, 0x50, 0x3E, 0x8C, 0xE2, 0x86, 0xE8, 0x5A, 0x34, 0x92, 0xFC, 0x4E, 0x20, 0x44, 0x2A, 0x98, 0xF6, 0x1A, 0x74, 0xC6, 0xA8, 0xCC, 0xA2, 0x10, 0x7E, 0xD8, 0xB6, 0x04, 0x6A, 0x0E, 0x60, 0xD2, 0xBC, 0xF0, 0x9E, 0x2C, 0x42, 0x26, 0x48, 0xFA, 0x94, 0x32, 0x5C, 0xEE, 0x80, 0xE4, 0x8A, 0x38, 0x56, 0xA0, 0xCE, 0x7C, 0x12, 0x76, 0x18, 0xAA, 0xC4, 0x62, 0x0C, 0xBE, 0xD0, 0xB4, 0xDA, 0x68, 0x06, 0x4A, 0x24, 0x96, 0xF8, 0x9C, 0xF2, 0x40, 0x2E, 0x88, 0xE6, 0x54, 0x3A, 0x5E, 0x30, 0x82, 0xEC }; //} unsigned char crcMediumEncode8 (unsigned char byte1) { unsigned char synd; synd = (byte1 ^ 0xEC); if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ 0x80; if (synd & 0x80) synd ^= 0xB7; return synd | 0x80; } // bool crcMediumCheck8 (unsigned char byte1, unsigned char byte2) { unsigned char synd; synd = (byte1 ^ 0xEC); if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ byte2; if (synd & 0x80) synd ^= 0xB7; return synd == 0; } // unsigned char propagate7 [128] = { 0x00, 0x6E, 0xDC, 0xB2, 0xD6, 0xB8, 0x0A, 0x64, 0xC2, 0xAC, 0x1E, 0x70, 0x14, 0x7A, 0xC8, 0xA6, 0xEA, 0x84, 0x36, 0x58, 0x3C, 0x52, 0xE0, 0x8E, 0x28, 0x46, 0xF4, 0x9A, 0xFE, 0x90, 0x22, 0x4C, 0xBA, 0xD4, 0x66, 0x08, 0x6C, 0x02, 0xB0, 0xDE, 0x78, 0x16, 0xA4, 0xCA, 0xAE, 0xC0, 0x72, 0x1C, 0x50, 0x3E, 0x8C, 0xE2, 0x86, 0xE8, 0x5A, 0x34, 0x92, 0xFC, 0x4E, 0x20, 0x44, 0x2A, 0x98, 0xF6, 0x1A, 0x74, 0xC6, 0xA8, 0xCC, 0xA2, 0x10, 0x7E, 0xD8, 0xB6, 0x04, 0x6A, 0x0E, 0x60, 0xD2, 0xBC, 0xF0, 0x9E, 0x2C, 0x42, 0x26, 0x48, 0xFA, 0x94, 0x32, 0x5C, 0xEE, 0x80, 0xE4, 0x8A, 0x38, 0x56, 0xA0, 0xCE, 0x7C, 0x12, 0x76, 0x18, 0xAA, 0xC4, 0x62, 0x0C, 0xBE, 0xD0, 0xB4, 0xDA, 0x68, 0x06, 0x4A, 0x24, 0x96, 0xF8, 0x9C, 0xF2, 0x40, 0x2E, 0x88, 0xE6, 0x54, 0x3A, 0x5E, 0x30, 0x82, 0xEC }; // unsigned char crcMediumEncode16 (unsigned char byte1, unsigned char byte2) { unsigned char synd; synd = (byte1 ^ 0xEC); if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ byte2; if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ 0x80; if (synd & 0x80) synd ^= 0xB7; return synd | 0x80; } // bool crcMediumCheck16 (unsigned char byte1, unsigned char byte2, unsigned char byte3) { unsigned char synd; synd = (byte1 ^ 0xEC); if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ byte2; if (synd & 0x80) synd ^= 0xB7; synd = propagate7[synd] ^ byte3; if (synd & 0x80) synd ^= 0xB7; return synd == 0; }
比較
為了了解這些CRC計(jì)算的效率,該代碼是在以24 MIPS(16MHz內(nèi)部CPU時(shí)鐘)運(yùn)行的Microchip PIC32F系列上實(shí)現(xiàn)的。這是一個(gè)具有 16 位指令的 24 位數(shù)據(jù)路徑微處理器。對(duì)代碼的唯一修改是將返回值更改為“short”,C 編譯器將其解釋為有符號(hào)的 16 位值,即其本機(jī)數(shù)據(jù)寬度。
代碼大小由編譯器和鏈接器表確定。輔助程序生成 1,024 個(gè)隨機(jī) 8 位、16 位或 24 位值。報(bào)告的時(shí)間是這 1,024 次測(cè)試的平均值。表1總結(jié)了使用Microchip C編譯器及其代碼仿真器獲得的數(shù)據(jù)。對(duì)于使用表查找的代碼,大小以字節(jié)為單位指定為 CONST。
算法 | 字節(jié)(PGM + CONST) | 編碼時(shí)間(μs) | 解碼時(shí)間(微秒) |
緊湊的單字節(jié) | 219 | 24.8 | 25.5 |
快速單字節(jié) | 570 (186 + 384) | 1.72 | 3.00 |
平衡單字節(jié) | 323 (195 + 128) | 2.06 | 2.44 |
緊湊雙字節(jié) | 267 | 37.2 | 37.8 |
快速雙字節(jié) | 723 (339 + 384) | 3.19 | 4.34 |
平衡雙字節(jié) | 473 (345 + 128) | 3.02 | 3.40 |
不同的微處理器會(huì)產(chǎn)生不同的結(jié)果,但在PIC24F的情況下,不需要使用快速算法。如果對(duì)快速CRC轉(zhuǎn)換感興趣,則應(yīng)在目標(biāo)處理器上對(duì)快速算法和平衡算法進(jìn)行基準(zhǔn)測(cè)試,以確定哪個(gè)更好。
結(jié)論
本應(yīng)用筆記介紹了如何在與MAX14900E八通道高速工業(yè)開(kāi)關(guān)通信的微處理器上對(duì)CRC算法進(jìn)行編碼。利用本應(yīng)用筆記中的C代碼示例是實(shí)現(xiàn)這種額外保護(hù)的無(wú)憂方法。
在某些情況下,應(yīng)在目標(biāo)處理器上執(zhí)行一些基準(zhǔn)測(cè)試,尤其是在優(yōu)先考慮快速執(zhí)行速度的情況下。
審核編輯:郭婷
-
微控制器
+關(guān)注
關(guān)注
48文章
7334瀏覽量
150080 -
crc
+關(guān)注
關(guān)注
0文章
197瀏覽量
29357 -
SPI
+關(guān)注
關(guān)注
17文章
1665瀏覽量
90710
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論