Go Down

Topic: Using the on board CRC Generator on the SAMD21 (Read 781 times) previous topic - next topic

bear_e97

I'm using the Arduino Zero board.

I've been trying to implement CRC in my program using the on board CRC generator.

I need to calculate the CRC of a string before transmitting it (CRC 16 or CRC 32). I am unable to implement it.

Is there any library that works with the Zero? If not, how do i program the on board registers to use the CRC generator?

Please help!  :(  :(  :(  :( 



MartinL

#1
Nov 27, 2018, 11:10 am Last Edit: Nov 27, 2018, 11:14 am by MartinL
Hi bear_e97,

The SAMD21's CRC engine is primarily designed to operate with the DMAC (Direct Memory Access Controller), although it can be accessed and used directly by the CPU.

The CRC engine can be used to process 8-bit BYTE, 16-bit HWORD and 32-bit WORD data, (although the CRC engine itself processes a byte at a time) and implements both CRC-16 and CRC-32.

The situation isn't helped by the fact that the SAMD21 datasheet contradicts itself over the CRCBUSY bit. It would've been better if they'd have called it CRCCOMPLETE. It also doesn't explain how to actually reset the CRC engine, (although I've included this at the bottom of the code below).

Here's an example of using the CRC engine to process an array of 4 data WORDs with CRC-16:

Code: [Select]
void setup()
{
  SerialUSB.begin(115200);                                // Open communications on native USB port
  while(!SerialUSB);                                      // Wait for the console to open
 
  uint32_t data[] = { 0, 1, 2, 3 };                       // Four data 32-bit WORDs
 
  DMAC->CRCCTRL.reg = DMAC_CRCCTRL_CRCPOLY_CRC16 |        // Use CRC16
                      //DMAC_CRCCTRL_CRCPOLY_CRC32 |        // Use CRC32
                      DMAC_CRCCTRL_CRCBEATSIZE_WORD |     // Process 4 byte WORD, (BYTE & HWORD also available)
                      DMAC_CRCCTRL_CRCSRC_IO;             // Use the IO interface                   

  DMAC->CTRL.bit.CRCENABLE = 1;                           // Enable the CRC engine

  for (uint8_t i = 0; i < 4; i++)                         
  { 
    DMAC->CRCDATAIN.reg = data[i];                        // Calculate CRC for each data[] WORD
    while(!DMAC->CRCSTATUS.bit.CRCBUSY);                  // Wait for the CRC engine to complete   
    DMAC->CRCSTATUS.bit.CRCBUSY = 1;                      // Clear the CRCBUSY flag
  }
  SerialUSB.println(DMAC->CRCCHKSUM.reg);                 // Output the CRC check sum

  DMAC->CTRL.bit.CRCENABLE = 0;                           // Reset the CRC engine
  DMAC->CRCDATAIN.reg = DMAC_CRCDATAIN_RESETVALUE;
  DMAC->CRCCHKSUM.reg = DMAC_CRCCHKSUM_RESETVALUE;
  DMAC->CTRL.bit.CRCENABLE = 1;
}

void loop(){}

MartinL

#2
Nov 27, 2018, 12:26 pm Last Edit: Nov 27, 2018, 12:32 pm by MartinL
Also, the CRC checksum should be appended to the data in little endian format by the encoder. This will generate a 0 checksum (for CRC-16) and set the CRCZERO bit in the CRCSTATUS register at the decoder:

Code: [Select]
// Append CRC-16 checksum to data in little endian format
DMAC->CRCDATAIN.reg = DMAC->CRCCHKSUM.reg >> 8 & 0x00FF | DMAC->CRCCHKSUM.reg << 8 & 0xFF00;    // Calcualte CRC checksum in little endian format
while(!DMAC->CRCSTATUS.bit.CRCBUSY);                    // Wait for the CRC engine to complete   
DMAC->CRCSTATUS.bit.CRCBUSY = 1;                        // Clear the CRCBUSY flag
SerialUSB.println(DMAC->CRCCHKSUM.reg);                 // Output the CRC check sum (should be 0)
SerialUSB.println(DMAC->CRCSTATUS.bit.CRCZERO);         // Check that the CRCZERO bit's been set

bear_e97


Go Up