Using the on board CRC Generator on the SAMD21

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! :frowning: :frowning: :frowning: :frowning:

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:

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(){}

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:

// 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

Hi MartinL,

Thank you so much!

:slight_smile: :slight_smile: