tom dunigan / FastCRC

Dependents:   fastCRCperf

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FastCRChw.cpp Source File

FastCRChw.cpp

00001 /* FastCRC library code is placed under the MIT license
00002  * Copyright (c) 2014,2015 Frank Bösing
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining
00005  * a copy of this software and associated documentation files (the
00006  * "Software"), to deal in the Software without restriction, including
00007  * without limitation the rights to use, copy, modify, merge, publish,
00008  * distribute, sublicense, and/or sell copies of the Software, and to
00009  * permit persons to whom the Software is furnished to do so, subject to
00010  * the following conditions:
00011  *
00012  * The above copyright notice and this permission notice shall be
00013  * included in all copies or substantial portions of the Software.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00016  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00018  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00019  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00020  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00021  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00022  * SOFTWARE.
00023  */
00024 
00025 //
00026 // HW-calculations are 32BIT
00027 //
00028 // Thanks to:
00029 // - Catalogue of parametrised CRC algorithms, CRC RevEng
00030 // http://reveng.sourceforge.net/crc-catalogue/
00031 //
00032 // - Danjel McGougan (CRC-Table-Generator)
00033 //
00034 
00035 
00036 #if defined(__CORTEX_M4) || defined(__MK20DX256__)
00037 
00038 
00039 #include "FastCRC.h"
00040 
00041 // ===============================================
00042 
00043 typedef struct {
00044   union {
00045       uint32_t CRC; //CRC Data register
00046       struct {
00047           uint16_t CRC16;
00048           uint16_t CRC16_1;
00049       };
00050       struct {
00051           uint8_t CRC8;
00052           uint8_t CRC8_1;
00053           uint8_t CRC8_2;
00054           uint8_t CRC8_3;
00055       };
00056   };
00057   uint32_t GPOLY; //CRC Polynomial register
00058   uint32_t CTRL;  //CRC Control register
00059 } CRC_T;
00060 
00061 static volatile CRC_T * const rCRC = (CRC_T *)0x40032000;
00062 
00063 #define CRC_CTRL_WAS   25 // Write CRC Data Register As Seed(1) / Data(0)
00064 #define CRC_CTRL_TCRC  24 // Width of CRC protocol (0=16 BIT, 1=32 BIT)
00065 #define CRC_CTRL_TOTR1 29 // TOTR[1]
00066 
00067 
00068 // ================= 8-BIT CRC ===================
00069 
00070 /** Constructor
00071  * Enables CRC-clock
00072  */
00073 FastCRC8::FastCRC8(){
00074   SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
00075 }
00076 
00077 /** SMBUS CRC
00078  * aka CRC-8
00079  * @param data Pointer to Data
00080  * @param datalen Length of Data
00081  * @return CRC value
00082  */
00083 uint8_t FastCRC8::smbus(const uint8_t *data, const uint16_t datalen)
00084 {
00085   // poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4
00086   return generic(0x07, 0, CRC_FLAG_NOREFLECT, data, datalen);
00087 }
00088 
00089 /** MAXIM 8-Bit CRC
00090  * equivalent to _crc_ibutton_update() in crc16.h from avr_libc
00091  * @param data Pointer to Data
00092  * @param datalen Length of Data
00093  * @return CRC value
00094  */
00095 uint8_t FastCRC8::maxim(const uint8_t *data, const uint16_t datalen)
00096 {
00097   // poly=0x31 init=0x00 refin=true refout=true xorout=0x00  check=0xa1
00098   return generic(0x31, 0, CRC_FLAG_REFLECT, data, datalen);
00099 }
00100 
00101 /** Update
00102  * Call for subsequent calculations with previous seed
00103  * @param data Pointer to Data
00104  * @param datalen Length of Data
00105  * @return CRC value
00106  */
00107 uint8_t FastCRC8::update(const uint8_t *data, const uint16_t datalen)
00108 {
00109 
00110   const uint8_t *src = data;
00111   const uint8_t *target = src + datalen;
00112 
00113   while (((uintptr_t)src & 0x03) != 0 && (src < target)) {
00114     rCRC->CRC8_3 = *src++; //Write 8 BIT
00115   }
00116 
00117   while (src <= target-4) {
00118     rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
00119     src += 4;
00120   }
00121 
00122   while (src < target) {
00123     rCRC->CRC8_3 = *src++; //Write 8 Bit
00124   }
00125 
00126   if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
00127     return rCRC->CRC8;
00128   else
00129     return rCRC->CRC8_3;
00130 }
00131 
00132 /** generic function for all 8-Bit CRCs
00133  * @param polynom Polynom
00134  * @param seed Seed
00135  * @param flags Flags
00136  * @param data Pointer to Data
00137  * @param datalen Length of Data
00138  * @return CRC value
00139  */
00140 uint8_t FastCRC8::generic(const uint8_t polynom, const uint8_t seed, const uint32_t flags, const uint8_t *data,const uint16_t datalen)
00141 {
00142 
00143   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);                      // 32Bit Mode, Prepare to write seed(25)
00144   rCRC->GPOLY = ((uint32_t)polynom)<<24;                                             // Set polynom
00145   rCRC->CRC   = ((uint32_t)seed<<24);                                                // Write seed
00146   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                                          // Clear WAS Bit - prepare to write data  
00147 
00148   return update(data, datalen);
00149 }
00150 uint8_t FastCRC8::smbus_upd(const uint8_t *data, uint16_t datalen){return update(data, datalen);}
00151 uint8_t FastCRC8::maxim_upd(const uint8_t *data, uint16_t datalen){return update(data, datalen);}
00152 
00153 // ================= 16-BIT CRC ===================
00154 
00155 /** Constructor
00156  * Enables CRC-clock
00157  */
00158 FastCRC16::FastCRC16(){
00159   SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
00160 }
00161 
00162 /** CCITT
00163  * Alias "false CCITT"
00164  * @param data Pointer to Data
00165  * @param datalen Length of Data
00166  * @return CRC value
00167  */
00168 uint16_t FastCRC16::ccitt(const uint8_t *data,const uint16_t datalen)
00169 {
00170  // poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
00171   return generic(0x1021, 0XFFFF, CRC_FLAG_NOREFLECT, data, datalen);
00172 }
00173 
00174 /** MCRF4XX
00175  * equivalent to _crc_ccitt_update() in crc16.h from avr_libc
00176  * @param data Pointer to Data
00177  * @param datalen Length of Data
00178  * @return CRC value
00179  */
00180 uint16_t FastCRC16::mcrf4xx(const uint8_t *data,const uint16_t datalen)
00181 {
00182  // poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91
00183   return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT, data, datalen);
00184 }
00185 
00186 /** MODBUS
00187  * equivalent to _crc_16_update() in crc16.h from avr_libc
00188  * @param data Pointer to Data
00189  * @param datalen Length of Data
00190  * @return CRC value
00191  */
00192 uint16_t FastCRC16::modbus(const uint8_t *data, const uint16_t datalen)
00193 {
00194  // poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37
00195   return generic(0x8005, 0XFFFF, CRC_FLAG_REFLECT, data, datalen);
00196 }
00197 
00198 /** KERMIT
00199  * Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
00200  * @param data Pointer to Data
00201  * @param datalen Length of Data
00202  * @return CRC value
00203  */
00204 uint16_t FastCRC16::kermit(const uint8_t *data, const uint16_t datalen)
00205 {
00206  // poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
00207  // sometimes byteswapped presentation of result
00208   return generic(0x1021, 0x00, CRC_FLAG_REFLECT, data, datalen);
00209 }
00210 
00211 /** XMODEM
00212  * Alias ZMODEM, CRC-16/ACORN
00213  * @param data Pointer to Data
00214  * @param datalen Length of Data
00215  * @return CRC value
00216  */
00217 uint16_t FastCRC16::xmodem(const uint8_t *data, const uint16_t datalen)
00218 {
00219   //width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
00220   return generic(0x1021, 0, CRC_FLAG_NOREFLECT, data, datalen);
00221 }
00222 
00223 /** X25
00224  * Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B
00225  * @param data Pointer to Data
00226  * @param datalen Length of Data
00227  * @return CRC value
00228  */
00229 uint16_t FastCRC16::x25(const uint8_t *data, const uint16_t datalen)
00230 {
00231   // poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e
00232   return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
00233 }
00234 
00235 /** Update
00236  * Call for subsequent calculations with previous seed
00237  * @param data Pointer to Data
00238  * @param datalen Length of Data
00239  * @return CRC value
00240  */
00241 uint16_t FastCRC16::update(const uint8_t *data, const uint16_t datalen)
00242 {
00243   const uint8_t *src = data;
00244   const uint8_t *target = src + datalen;
00245 
00246   while (((uintptr_t)src & 0x03) !=0 && (src < target))  {
00247     rCRC->CRC8_3 = *src++; //Write 8 BIT
00248   }
00249 
00250   while (src <= target-4) {
00251     rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
00252     src += 4;
00253   }
00254 
00255   while (src < target) {
00256     rCRC->CRC8_3 = *src++; //Write 8 Bit
00257   }
00258 
00259   if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
00260     return rCRC->CRC16;
00261   else
00262     return rCRC->CRC16_1;
00263 }
00264 
00265 /** generic function for all 16-Bit CRCs
00266  * @param polynom Polynom
00267  * @param seed Seed
00268  * @param flags Flags
00269  * @param data Pointer to Data
00270  * @param datalen Length of Data
00271  * @return CRC value
00272  */
00273 uint16_t FastCRC16::generic(const uint16_t polynom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const uint16_t datalen)
00274 {
00275 
00276   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);// 32-Bit Mode, prepare to write seed(25)
00277   rCRC->GPOLY = ((uint32_t)polynom)<<16;                       // set polynom
00278   rCRC->CRC   = ((uint32_t)seed<<16);                          // this is the seed
00279   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                    // Clear WAS Bit - prepare to write data
00280 
00281   return update(data, datalen);
00282 }
00283 
00284 uint16_t FastCRC16::ccitt_upd(const uint8_t *data, uint16_t len)  {return update(data, len);}
00285 uint16_t FastCRC16::mcrf4xx_upd(const uint8_t *data, uint16_t len){return update(data, len);}
00286 uint16_t FastCRC16::kermit_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
00287 uint16_t FastCRC16::modbus_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
00288 uint16_t FastCRC16::xmodem_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
00289 uint16_t FastCRC16::x25_upd(const uint8_t *data, uint16_t len)    {return update(data, len);}
00290 
00291 
00292 
00293 // ================= 32-BIT CRC ===================
00294 
00295 /** Constructor
00296  * Enables CRC-clock
00297  */
00298 FastCRC32::FastCRC32(){
00299   SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
00300 }
00301 
00302 /** CRC32
00303  * Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
00304  * @param data Pointer to Data
00305  * @param datalen Length of Data
00306  * @return CRC value
00307  */
00308 uint32_t FastCRC32::crc32(const uint8_t *data, const uint16_t datalen)
00309 {
00310   // poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926
00311   return generic(0x04C11DB7L, 0XFFFFFFFFL, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
00312 }
00313 
00314 /** CKSUM
00315  * Alias CRC-32/POSIX
00316  * @param data Pointer to Data
00317  * @param datalen Length of Data
00318  * @return CRC value
00319  */
00320 uint32_t FastCRC32::cksum(const uint8_t *data, const uint16_t datalen)
00321 {
00322   // width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680
00323   return generic(0x04C11DB7L, 0, CRC_FLAG_NOREFLECT | CRC_FLAG_XOR, data, datalen);
00324 }
00325 
00326 /** Update
00327  * Call for subsequent calculations with previous seed
00328  * @param data Pointer to Data
00329  * @param datalen Length of Data
00330  * @return CRC value
00331  */
00332 //#pragma GCC diagnostic ignored "-Wpointer-arith"
00333 uint32_t FastCRC32::update(const uint8_t *data, const uint16_t datalen)
00334 {
00335 
00336   const uint8_t *src = data;
00337   const uint8_t *target = src + datalen;
00338 
00339   while (((uintptr_t)src & 0x03) != 0  && (src < target)) {
00340     rCRC->CRC8_3 = *src++; //Write 8 BIT
00341   }
00342 
00343   while (src <= target-4) {
00344     rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
00345     src += 4;
00346   }
00347 
00348   while (src < target) {
00349     rCRC->CRC8_3 = *src++; //Write 8 Bit
00350   }
00351 
00352   return rCRC->CRC;
00353 }
00354 
00355 /** generic function for all 32-Bit CRCs
00356  * @param polynom Polynom
00357  * @param seed Seed
00358  * @param flags Flags
00359  * @param data Pointer to Data
00360  * @param datalen Length of Data
00361  * @return CRC value
00362  */
00363 uint32_t FastCRC32::generic(const uint32_t polynom, const uint32_t seed, const uint32_t flags, const uint8_t *data, const uint16_t datalen)
00364 {
00365 
00366   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS); // 32Bit Mode, prepare to write seed(25)
00367   rCRC->GPOLY = polynom;                                        // Set polynom
00368   rCRC->CRC   = seed;                                           // This is the seed
00369   rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                     // Clear WAS Bit - prepare to write data
00370 
00371   return update(data, datalen);
00372 }
00373 
00374 uint32_t FastCRC32::crc32_upd(const uint8_t *data, uint16_t len){return update(data, len);}
00375 uint32_t FastCRC32::cksum_upd(const uint8_t *data, uint16_t len){return update(data, len);}
00376 
00377 #endif // __MK20DX128__ || __MK20DX256__