DMACに含まれているCRCエンジンを調べてみた。とりあえずDMACとは関係なく使えるようなので試してみたら以外に使いやすくてソフトウェアで計算するよりはかなり速いことがわかった。
さらにDMACと組み合わせるとmemcpy()の半分程度の時間でメモリコピーとCRC生成が同時実行できてしまう。これは使わないと損だということで、まずは、CRCエンジン単体のライブラリを作ってみた。
DMACを使わない場合はソフトウェアでデータを読み取る時間がかかるものの、それでもmemcpy()と同程度の時間でCRC(16/32)生成が出来てしまうなんて素晴らしいというしかない。
【サンプル・スケッチ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include <string.h> #include "Arduino.h" #include "crcengine.h" char *data = "123456789"; void setup(void) { Serial.begin(115200); while(!Serial) yield(); uint32_t crc16, crc32; CRCEngine::calc(data, strlen(data), &crc16, CRCENGINE_POLY_CRC16); CRCEngine::calc(data, strlen(data), &crc32, CRCENGINE_POLY_CRC32); Serial.print("data = \""); Serial.print(data); Serial.println("\""); Serial.print("crc16 = "); Serial.print(crc16, HEX); Serial.print(", crc32 = "); Serial.println(crc32, HEX); } void loop(void) { } [実行結果] data = "123456789" crc16 = 29B1, crc32 = CBF43926 |
【修正履歴】
2020-05-20
型名を変更。
【ライブラリ】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
/* crcengine.h - DMAC-CRC Library for Microchip ATSAMD21 (Cortex®-M0+) CRC polynomial selectable to – CRC-16 (CRC-CCITT) – CRC-32 (IEEE 802.3) Copyright (c) 2020 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __CRCENGINE_H #define __CRCENGINE_H #include <stdint.h> #include <stdbool.h> #include "sam.h" typedef enum { CRCENGINE_POLY_CRC16 = DMAC_CRCCTRL_CRCPOLY_CRC16_Val, // CRC-CCITT CRCENGINE_POLY_CRC32 = DMAC_CRCCTRL_CRCPOLY_CRC32_Val, // IEEE 802.3 } CRCENGINE_POLY; typedef enum { CRCENGINE_SOURCE_NOACT = 0x00, // NOACT No action CRCENGINE_SOURCE_IO = 0x01, // I/O interface CRCENGINE_SOURCE_DMA_0 = 0x20, // DMA channel 0 CRCENGINE_SOURCE_DMA_1 = 0x21, // DMA channel 1 CRCENGINE_SOURCE_DMA_2 = 0x22, // DMA channel 2 CRCENGINE_SOURCE_DMA_3 = 0x23, // DMA channel 3 CRCENGINE_SOURCE_DMA_4 = 0x24, // DMA channel 4 CRCENGINE_SOURCE_DMA_5 = 0x25, // DMA channel 5 CRCENGINE_SOURCE_DMA_6 = 0x26, // DMA channel 6 CRCENGINE_SOURCE_DMA_7 = 0x27, // DMA channel 7 CRCENGINE_SOURCE_DMA_8 = 0x28, // DMA channel 8 CRCENGINE_SOURCE_DMA_9 = 0x29, // DMA channel 9 CRCENGINE_SOURCE_DMA_10 = 0x2A, // DMA channel 10 CRCENGINE_SOURCE_DMA_11 = 0x2B, // DMA channel 11 CRCENGINE_SOURCE_DMA_12 = 0x2C, // DMA channel 12 } CRCENGINE_SOURCE; typedef enum { CRCENGINE_BEATSIZE_BYTE = DMAC_CRCCTRL_CRCBEATSIZE_BYTE_Val, CRCENGINE_BEATSIZE_HWORD = DMAC_CRCCTRL_CRCBEATSIZE_HWORD_Val, CRCENGINE_BEATSIZE_WORD = DMAC_CRCCTRL_CRCBEATSIZE_WORD_Val, } CRCENGINE_BEATSIZE; #define CRCENGINE_INIT 0xFFFFFFFFUL class CRCEngine { public: static bool calc(void *buf, uint16_t len, uint32_t *result, CRCENGINE_POLY poly = CRCENGINE_POLY_CRC16, uint32_t init = CRCENGINE_INIT) { if (busy()) return false; start(poly, init); uint8_t *p = (uint8_t *)buf; while (len--) datain(*p++); return checksum(result); } static bool busy(void) { return DMAC->CRCSTATUS.bit.CRCBUSY; } static void start(CRCENGINE_POLY poly, uint32_t init = CRCENGINE_INIT, CRCENGINE_SOURCE source = CRCENGINE_SOURCE_IO, CRCENGINE_BEATSIZE size = CRCENGINE_BEATSIZE_BYTE) { DMAC->CTRL.bit.CRCENABLE = 0; DMAC->CRCCHKSUM.reg = init; DMAC->CRCCTRL.bit.CRCSRC = source; DMAC->CRCCTRL.bit.CRCPOLY = poly; DMAC->CRCCTRL.bit.CRCBEATSIZE = size; DMAC->CTRL.bit.CRCENABLE = 1; } static void datain(uint32_t value) { DMAC->CRCDATAIN.reg = value; } static bool checksum(uint32_t *result) { if (DMAC->CRCCTRL.bit.CRCSRC == CRCENGINE_SOURCE_IO) DMAC->CRCSTATUS.bit.CRCBUSY = 1; if (busy()) return false; *result = DMAC->CRCCHKSUM.reg; return true; } }; #endif |