Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is tmc2209 stepper driver IC calculating CRC?

Tags:

c

uart

crc

I have tmc2209 stepper driver. I am planning to use UART for communication. The communication protocol looks pretty simple, but I can't figure out how to calculate this damn CRC. The polynomial is CRC-8 0x07. For the message 0x05 0x00 0x00 the correct CRC is 0x48 and for message 0x05 0x00 0x06 is correct CRC 0x6F. I know this because I have brute forced all possible combinations for these messages and with correct CRC tmc2209 responses. When I calculate CRC manually for these messages it doesn't match. They have some CRC example calculation in datasheet but this code looks broken for me. Here is the datasheet: https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2209_Datasheet_V103.pdf UART starts at page 15 and CRC calculation is on page 17.

like image 970
andz Avatar asked Oct 17 '25 17:10

andz


2 Answers

CRC located in last byte of message, add return datagram[datagramLength - 1]; on last method, you will get that crc value. Look at this:

#include <stdio.h>
#include <stdint.h>

uint8_t swuart_calcCRC (uint8_t * datagram, uint8_t datagramLength) {
  int i, j;
  uint8_t *crc = datagram + (datagramLength - 1);   // CRC located in last byte of message
  uint8_t currentByte;
  *crc = 0;
  for (i = 0; i < (datagramLength - 1); i++) {      // Execute for all bytes of a message
      currentByte = datagram[i];                    // Retrieve a byte to be sent from Array
      for (j = 0; j < 8; j++) {
          if ((*crc >> 7) ^ (currentByte & 0x01)) { // update CRC based result of XOR operation
              *crc = (*crc << 1) ^ 0x07;
          }
          else {
              *crc = (*crc << 1);
          }
          currentByte = currentByte >> 1;
      }         // for CRC bit
  }             // for message byte
  return datagram[datagramLength - 1];
}


int main () {
  uint8_t datagram1[] = { 0x05, 0x00, 0x00, 0x00 };
  uint8_t datagram2[] = { 0x05, 0x00, 0x06, 0x00 };
  uint8_t length = 4;

  uint8_t crc1 = swuart_calcCRC (datagram1, length);
  printf ("crc1: %02X\n", crc1);

  uint8_t crc2 = swuart_calcCRC (datagram2, length);
  printf ("crc2: %02X\n", crc2);

  return 0;
}

Result:

crc1: 48
crc2: 6F
like image 186
Ihdina Avatar answered Oct 20 '25 09:10

Ihdina


Documentation from your link says:

An 8 bit CRC polynomial is used for checking both read and write access. It allows detection of up to eight single bit errors. The CRC8-ATM polynomial with an initial value of zero is applied LSB to MSB, including the sync- and addressing byte. The sync nibble is assumed to always be correct. The TMC2209 responds only to correctly transmitted datagrams containing its own slave address. It increases its datagram counter for each correctly received write access datagram.

X^8 + X^2 + X^1 + X^0

And start value is 0

And even code is provided

void swuart_calcCRC(UCHAR* datagram, UCHAR datagramLength)
{
 int i,j;
 UCHAR* crc = datagram + (datagramLength-1); // CRC located in last byte of message
 UCHAR currentByte;
 *crc = 0;
 for (i=0; i<(datagramLength-1); i++) { // Execute for all bytes of a message
 currentByte = datagram[i]; // Retrieve a byte to be sent from Array
 for (j=0; j<8; j++) {
 if ((*crc >> 7) ^ (currentByte&0x01)) // update CRC based result of XOR operation
 {
 *crc = (*crc << 1) ^ 0x07;
 }
 else
 {
 *crc = (*crc << 1);
 }
 currentByte = currentByte >> 1;
 } // for CRC bit
 } // for message byte
}
like image 34
tilz0R Avatar answered Oct 20 '25 07:10

tilz0R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!