-1

I am trying to interface with an EPOS2 motor controller over RS232 Serial with an Arduino Duemilanove (because it's what I had lying around). I got it to work for the most part - I can send and recieve data when I manually calculate the CRC checksum - but I'm trying to dynamically control the velocity of the motor which requires changing data, and therefore, changing checksum. The documentation for calculating the checksum is here, on page 24:

http://www.maxonmotorusa.com/medias/sys_master/8806425067550/EPOS2-Communication-Guide-En.pdf

I copied the code directly out of this documentation, and integrated it into my code, and it does not calculate the checksum correctly. Below is a shortened version of my full sketch (tested, yielding 0x527C). The weirdest part is that it calculates a different value in my full sketch than in the one below, but both are wrong. Is there something obvious that I'm missing?

byte comms[6] = { 0x10, 0x01, 0x03, 0x20, 0x01, 0x02 }; // CRC should be 0xA888

void setup() {
  Serial.begin(115200);
}

void loop() {
  calcCRC(comms, 6, true);
  while(1);
}

word calcCRC(byte *comms, int commsSize, boolean talkative) {
  int warraySize = commsSize / 2 + commsSize % 2;
  word warray[warraySize];

  warray[0] = comms[0] << 8 | comms[1];
  Serial.println(warray[0], HEX);

  for (int i = 1; i <= warraySize - 1; i++) {
    warray[i] = comms[i * 2 + 1] << 8 | comms[i * 2];
    Serial.println(warray[i], HEX);
  }

  word* warrayP = warray;

  word shifter, c;
  word carry;
  word CRC = 0;


  //Calculate pDataArray Word by Word
  while (commsSize--)
  {
    shifter = 0x8000;
    c = *warrayP ++;
    do {
      carry = CRC & 0x8000;
      CRC <<= 1;
      if (c & shifter) CRC++;
      if (carry) CRC ^= 0x1021;
      shifter >>= 1;
    } while (shifter);
  }

  if (talkative) {
    Serial.print("the CRC for this data is ");
    Serial.println(CRC, HEX);
  }

  return CRC;
}

I used the link below to calculate the checksum that works for this data:

https://www.ghsi.de/CRC/index.php?Polynom=10001000000100001&Message=1001+2003+0201

Thanks so much!!

1 Answers1

0

Where to begin.

First off, you are using commsSize-- for your loop, which will go through six times when you have only three words in the warray. So you are doing an out-of-bounds access of warray, and will necessarily get a random result (or crash).

Second, the build of your first word is backwards from your other builds. Your online CRC suffers the same problem, so you apparently don't even have a reliable test case.

Third (not an issue for the test case), if you have an odd number of bytes of input, you are doing an out-of-bounds access of comms to fill out the last word. And you are running the CRC bits too many times, unless the specification directs some sort of padding in that case. (Your documentation link is broken so I can't see what's supposed to happen.) Even then, you are using random data for the padding instead of zeros.

The whole word conversion thing is a waste of time anyway. You can just do it a byte at a time, given the proper ordering of the bytes. That also avoids the odd-number-of-bytes problem. This will produce the 0xa888 from the input you gave the online CRC calculator (which are your bytes in a messed up order, but exactly as you gave them to the calculator):

unsigned char dat[6] = { 0x10, 0x01, 0x20, 0x03, 0x02, 0x01 };

unsigned crc1021(unsigned char *dat, int len) {
    unsigned crc = 0;
    while (len) {
        crc ^= *dat++ << 8;
        for (int k = 0; k < 8; k++)
            crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
        len--;
    }
    return crc & 0xffff;
}
Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Thanks! This was helpful! The document link worked on multiple device, I apologize for that. I did it with words because that's how the documentation did it. Also, the byte order was "messed up" because that is the order that the EPOS needs to get them. To be honest I probably could have commented my code better... Thanks again for the help! – Rachael Putnam Jun 06 '16 at 13:58