CRC-32 different on nano and micro

Hello folks !

I have a problem here, trying to generate a crc and i get different results for the same data on a nano and a micro.

I have been using the same method for sending crc to my python program and i had no problems with it.

static PROGMEM prog_uint32_t crc_table[16] = {
  0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

unsigned long crc_update(unsigned long crc, byte data)
{
  byte tbl_idx;
  tbl_idx = crc ^ (data >> (0 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  tbl_idx = crc ^ (data >> (1 * 4));
  crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
  return crc;
}

unsigned long crc_string_char(char *s)
{
  unsigned long crc = ~0L;
  while (*s)
    crc = crc_update(crc, *s++);
  crc = ~crc;
  return crc;
}

unsigned long crc_string_byte(byte *s)
{
  unsigned long crc = ~0L;
  while (*s)
    crc = crc_update(crc, *s++);
  crc = ~crc;
  return crc;
}

#include <Wire.h>
#include "struct.h"


RGB example = { 1 , 1 , 1 };

byte start = 0x85;

void setup() {
  // put your setup code here, to run once:
  Wire.begin(0x10);
  Serial.begin(57600);
  delay(5000);
  Serial.println(crc_string_byte((byte*)&example));
  example.r = 7;
  Serial.println(crc_string_byte((byte*)&example), HEX);
  Serial.println(crc_string_byte((byte*)&example));
  Serial.println(example.r);  
  Serial.println(sizeof(example));
  
}

I flashed this code on both chips and get different results, how can that be ?

Thankful for any hint !

The crc_string_byte function is written to deal with a NULL-terminated character array but you are passing it an RGB struct which is presumably just three characters long (you didn't show us what is in struct.h). When the sketch is compiled on the two different types of processor there is no guarantee that the RGB struct will be followed with exactly the same data. You should write crc_string_byte (or a new function) so that you also specify the length of the data to be processed.

Pete

Struct.h

typedef struct {
  byte r;
  byte g;
  byte b;
} RGB;

Like i said i use the same sketch on both chips so i thought showing it had no purpose.

The crc_string_byte function is written to deal with a NULL-terminated character array but you are passing it an RGB struct

There is another function called _char who does that and even if i pass chars the crc is calculated with math and chars are just values like bytes (just interpreted differently) so why should it not work ? You don´t need to use a null terminatedchar array, terminating it will affect the crc (i tested it and decided to leave it out).

In my Python program i usechecksum = (hex(binascii.crc32(data) & 0xffffffff)) in order to have the same results on the microchip and my pc, maybe i have to do sth. similar for both chip architectures ?

When the sketch is compiled on the two different types of processor there is no guarantee that the RGB struct will be followed with exactly the same data

Can you tell me why ? And how should i ever compare a crc of a struct then ?

You call the function like this:

Serial.println(crc_string_byte((byte*)&example));

and the main part of the function itself does this:

  while (*s)
    crc = crc_update(crc, *s++);

which computes the CRC on a sequence of characters until it encounters a NULL byte.

Like I said, you need to write a function to which you also pass the number of bytes you want to be processed, so that you would call it like this, for example:

Serial.println(crc_number_byte((byte*)&example,sizeof(example)));

This is how you would handle the CRC of a struct or any other data which is not a NULL-terminated string.

Pete

Thanks for you input !

I will try it out.

Edit
It worked thank you very much !

unsigned long crc_string_byte(byte *s, unsigned int length)
{
  unsigned long crc = ~0L;
  byte x= 0;
  while (x<length){
    crc = crc_update(crc, *s++);
    x++;
  }  
  crc = ~crc;
  return crc;
}

I still dont get why it is working with no null-terminated character arrays, on pc and on my nano (tried a lot of different messages, up to 60 chars long)

while (*s) is looking if there is still data in the ram at the adress, increasing every time ?

Fortunately, the data space of most programs is pretty full of bytes that are 0, and will therefore look like string terminations (for example, any "int" whose value is currently 0xFF or less.)

0 and \0 is the same ?

seems like, wasn´t aware of that http://www.asciitable.com/

0 and \0 is the same ?

Yes - and no. It depends on the context. For example "0\0" is an ASCII character for zero followed by a null.

If you had been using a NULL terminated string there would have been no problem. For example, this would always work:

unsigned long crc_result = crc_string_char("Hello there");

because there is a NULL at the end of the string no matter which compiler you use. It is part of the language specification that a string constant includes a NULL at the end - you don't have to write the string as "Hello there\0" to get the null. But when you define your RGB struct or use an array, there is no implicit termination character. You defined the RGB struct to be three characters and that is all you get.

while (*s) is looking if there is still data in the ram at the adress, increasing every time ?

Yes, it will keep going until it encounters a NULL byte. On an arduino, if by some weird fluke there are no NULL bytes anywhere in memory, the address will "wrap around" back to address zero and keep going and never stop.

Pete

Thanks el_supremo for pointing it out, now i understand why it worked :)