Port of teensy 3 FastCRC library, uses hardware CRC

Dependents:   fastCRCperf

Port of teensy 3 FastCRC library, uses hardware CRC on K64F. About 30 times faster than Arduino CRC (crc16.h).

https://github.com/FrankBoesing/FastCRC

teensy forum discussions on FastCRC https://forum.pjrc.com/threads/25699-Fast-CRC-library-(uses-the-built-in-crc-module-in-Teensy3)

Revision:
0:7343f324d853
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FastCRChw.cpp	Fri Apr 22 09:51:51 2016 +0000
@@ -0,0 +1,377 @@
+/* FastCRC library code is placed under the MIT license
+ * Copyright (c) 2014,2015 Frank Bösing
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+//
+// HW-calculations are 32BIT
+//
+// Thanks to:
+// - Catalogue of parametrised CRC algorithms, CRC RevEng
+// http://reveng.sourceforge.net/crc-catalogue/
+//
+// - Danjel McGougan (CRC-Table-Generator)
+//
+
+
+#if defined(__CORTEX_M4) || defined(__MK20DX256__)
+
+
+#include "FastCRC.h"
+
+// ===============================================
+
+typedef struct {
+  union {
+      uint32_t CRC; //CRC Data register
+      struct {
+          uint16_t CRC16;
+          uint16_t CRC16_1;
+      };
+      struct {
+          uint8_t CRC8;
+          uint8_t CRC8_1;
+          uint8_t CRC8_2;
+          uint8_t CRC8_3;
+      };
+  };
+  uint32_t GPOLY; //CRC Polynomial register
+  uint32_t CTRL;  //CRC Control register
+} CRC_T;
+
+static volatile CRC_T * const rCRC = (CRC_T *)0x40032000;
+
+#define CRC_CTRL_WAS   25 // Write CRC Data Register As Seed(1) / Data(0)
+#define CRC_CTRL_TCRC  24 // Width of CRC protocol (0=16 BIT, 1=32 BIT)
+#define CRC_CTRL_TOTR1 29 // TOTR[1]
+
+
+// ================= 8-BIT CRC ===================
+
+/** Constructor
+ * Enables CRC-clock
+ */
+FastCRC8::FastCRC8(){
+  SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
+}
+
+/** SMBUS CRC
+ * aka CRC-8
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint8_t FastCRC8::smbus(const uint8_t *data, const uint16_t datalen)
+{
+  // poly=0x07 init=0x00 refin=false refout=false xorout=0x00 check=0xf4
+  return generic(0x07, 0, CRC_FLAG_NOREFLECT, data, datalen);
+}
+
+/** MAXIM 8-Bit CRC
+ * equivalent to _crc_ibutton_update() in crc16.h from avr_libc
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint8_t FastCRC8::maxim(const uint8_t *data, const uint16_t datalen)
+{
+  // poly=0x31 init=0x00 refin=true refout=true xorout=0x00  check=0xa1
+  return generic(0x31, 0, CRC_FLAG_REFLECT, data, datalen);
+}
+
+/** Update
+ * Call for subsequent calculations with previous seed
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint8_t FastCRC8::update(const uint8_t *data, const uint16_t datalen)
+{
+
+  const uint8_t *src = data;
+  const uint8_t *target = src + datalen;
+
+  while (((uintptr_t)src & 0x03) != 0 && (src < target)) {
+    rCRC->CRC8_3 = *src++; //Write 8 BIT
+  }
+
+  while (src <= target-4) {
+    rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
+    src += 4;
+  }
+
+  while (src < target) {
+    rCRC->CRC8_3 = *src++; //Write 8 Bit
+  }
+
+  if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
+    return rCRC->CRC8;
+  else
+    return rCRC->CRC8_3;
+}
+
+/** generic function for all 8-Bit CRCs
+ * @param polynom Polynom
+ * @param seed Seed
+ * @param flags Flags
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint8_t FastCRC8::generic(const uint8_t polynom, const uint8_t seed, const uint32_t flags, const uint8_t *data,const uint16_t datalen)
+{
+
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);                      // 32Bit Mode, Prepare to write seed(25)
+  rCRC->GPOLY = ((uint32_t)polynom)<<24;                                             // Set polynom
+  rCRC->CRC   = ((uint32_t)seed<<24);                                                // Write seed
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                                          // Clear WAS Bit - prepare to write data  
+
+  return update(data, datalen);
+}
+uint8_t FastCRC8::smbus_upd(const uint8_t *data, uint16_t datalen){return update(data, datalen);}
+uint8_t FastCRC8::maxim_upd(const uint8_t *data, uint16_t datalen){return update(data, datalen);}
+
+// ================= 16-BIT CRC ===================
+
+/** Constructor
+ * Enables CRC-clock
+ */
+FastCRC16::FastCRC16(){
+  SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
+}
+
+/** CCITT
+ * Alias "false CCITT"
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::ccitt(const uint8_t *data,const uint16_t datalen)
+{
+ // poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1
+  return generic(0x1021, 0XFFFF, CRC_FLAG_NOREFLECT, data, datalen);
+}
+
+/** MCRF4XX
+ * equivalent to _crc_ccitt_update() in crc16.h from avr_libc
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::mcrf4xx(const uint8_t *data,const uint16_t datalen)
+{
+ // poly=0x1021 init=0xffff refin=true refout=true xorout=0x0000 check=0x6f91
+  return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT, data, datalen);
+}
+
+/** MODBUS
+ * equivalent to _crc_16_update() in crc16.h from avr_libc
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::modbus(const uint8_t *data, const uint16_t datalen)
+{
+ // poly=0x8005 init=0xffff refin=true refout=true xorout=0x0000 check=0x4b37
+  return generic(0x8005, 0XFFFF, CRC_FLAG_REFLECT, data, datalen);
+}
+
+/** KERMIT
+ * Alias CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::kermit(const uint8_t *data, const uint16_t datalen)
+{
+ // poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189
+ // sometimes byteswapped presentation of result
+  return generic(0x1021, 0x00, CRC_FLAG_REFLECT, data, datalen);
+}
+
+/** XMODEM
+ * Alias ZMODEM, CRC-16/ACORN
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::xmodem(const uint8_t *data, const uint16_t datalen)
+{
+  //width=16 poly=0x1021 init=0x0000 refin=false refout=false xorout=0x0000 check=0x31c3
+  return generic(0x1021, 0, CRC_FLAG_NOREFLECT, data, datalen);
+}
+
+/** X25
+ * Alias CRC-16/IBM-SDLC, CRC-16/ISO-HDLC, CRC-B
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::x25(const uint8_t *data, const uint16_t datalen)
+{
+  // poly=0x1021 init=0xffff refin=true refout=true xorout=0xffff check=0x906e
+  return generic(0x1021, 0XFFFF, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
+}
+
+/** Update
+ * Call for subsequent calculations with previous seed
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::update(const uint8_t *data, const uint16_t datalen)
+{
+  const uint8_t *src = data;
+  const uint8_t *target = src + datalen;
+
+  while (((uintptr_t)src & 0x03) !=0 && (src < target))  {
+    rCRC->CRC8_3 = *src++; //Write 8 BIT
+  }
+
+  while (src <= target-4) {
+    rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
+    src += 4;
+  }
+
+  while (src < target) {
+    rCRC->CRC8_3 = *src++; //Write 8 Bit
+  }
+
+  if (rCRC->CTRL & (1<<CRC_CTRL_TOTR1))
+    return rCRC->CRC16;
+  else
+    return rCRC->CRC16_1;
+}
+
+/** generic function for all 16-Bit CRCs
+ * @param polynom Polynom
+ * @param seed Seed
+ * @param flags Flags
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint16_t FastCRC16::generic(const uint16_t polynom, const uint16_t seed, const uint32_t flags, const uint8_t *data, const uint16_t datalen)
+{
+
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS);// 32-Bit Mode, prepare to write seed(25)
+  rCRC->GPOLY = ((uint32_t)polynom)<<16;                       // set polynom
+  rCRC->CRC   = ((uint32_t)seed<<16);                          // this is the seed
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                    // Clear WAS Bit - prepare to write data
+
+  return update(data, datalen);
+}
+
+uint16_t FastCRC16::ccitt_upd(const uint8_t *data, uint16_t len)  {return update(data, len);}
+uint16_t FastCRC16::mcrf4xx_upd(const uint8_t *data, uint16_t len){return update(data, len);}
+uint16_t FastCRC16::kermit_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
+uint16_t FastCRC16::modbus_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
+uint16_t FastCRC16::xmodem_upd(const uint8_t *data, uint16_t len) {return update(data, len);}
+uint16_t FastCRC16::x25_upd(const uint8_t *data, uint16_t len)    {return update(data, len);}
+
+
+
+// ================= 32-BIT CRC ===================
+
+/** Constructor
+ * Enables CRC-clock
+ */
+FastCRC32::FastCRC32(){
+  SIM_SCGC6 |= SIM_SCGC6_CRC_MASK;
+}
+
+/** CRC32
+ * Alias CRC-32/ADCCP, PKZIP, Ethernet, 802.3
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint32_t FastCRC32::crc32(const uint8_t *data, const uint16_t datalen)
+{
+  // poly=0x04c11db7 init=0xffffffff refin=true refout=true xorout=0xffffffff check=0xcbf43926
+  return generic(0x04C11DB7L, 0XFFFFFFFFL, CRC_FLAG_REFLECT | CRC_FLAG_XOR, data, datalen);
+}
+
+/** CKSUM
+ * Alias CRC-32/POSIX
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint32_t FastCRC32::cksum(const uint8_t *data, const uint16_t datalen)
+{
+  // width=32 poly=0x04c11db7 init=0x00000000 refin=false refout=false xorout=0xffffffff check=0x765e7680
+  return generic(0x04C11DB7L, 0, CRC_FLAG_NOREFLECT | CRC_FLAG_XOR, data, datalen);
+}
+
+/** Update
+ * Call for subsequent calculations with previous seed
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+//#pragma GCC diagnostic ignored "-Wpointer-arith"
+uint32_t FastCRC32::update(const uint8_t *data, const uint16_t datalen)
+{
+
+  const uint8_t *src = data;
+  const uint8_t *target = src + datalen;
+
+  while (((uintptr_t)src & 0x03) != 0  && (src < target)) {
+    rCRC->CRC8_3 = *src++; //Write 8 BIT
+  }
+
+  while (src <= target-4) {
+    rCRC->CRC = *( uint32_t  *)src; //Write 32 BIT
+    src += 4;
+  }
+
+  while (src < target) {
+    rCRC->CRC8_3 = *src++; //Write 8 Bit
+  }
+
+  return rCRC->CRC;
+}
+
+/** generic function for all 32-Bit CRCs
+ * @param polynom Polynom
+ * @param seed Seed
+ * @param flags Flags
+ * @param data Pointer to Data
+ * @param datalen Length of Data
+ * @return CRC value
+ */
+uint32_t FastCRC32::generic(const uint32_t polynom, const uint32_t seed, const uint32_t flags, const uint8_t *data, const uint16_t datalen)
+{
+
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC) | (1<<CRC_CTRL_WAS); // 32Bit Mode, prepare to write seed(25)
+  rCRC->GPOLY = polynom;                                        // Set polynom
+  rCRC->CRC   = seed;                                           // This is the seed
+  rCRC->CTRL  = flags | (1<<CRC_CTRL_TCRC);                     // Clear WAS Bit - prepare to write data
+
+  return update(data, datalen);
+}
+
+uint32_t FastCRC32::crc32_upd(const uint8_t *data, uint16_t len){return update(data, len);}
+uint32_t FastCRC32::cksum_upd(const uint8_t *data, uint16_t len){return update(data, len);}
+
+#endif // __MK20DX128__ || __MK20DX256__
\ No newline at end of file