CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

CRC-32 with built-in hardware on dsPIC33E

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
opAmp



Joined: 09 Aug 2022
Posts: 4
Location: Norway

View user's profile Send private message

CRC-32 with built-in hardware on dsPIC33E
PostPosted: Tue Aug 09, 2022 8:39 pm     Reply with quote

Hi,

I have a problem calculating CRC-32 using the hardware-based CRC functions on a dsPIC33E. I attempt to calculate the CRC-32 on the ASCII string "abc", using this generator polynomial: 0xEDB88320

The result should be 0x352441C2 - this can be verified here:
https://www.scadacore.com/tools/programming-calculators/online-checksum-calculator/

I have also tried with C code from the following web page to calculate the CRC-32 in software, and I get the same result 0x352441C2:
http://home.thep.lu.se/~bjorn/crc/

I even implemented CRC-32 in JavaScript, and I got the same result 0x352441C2.

Here is my problematic implementation in PCD v5.109:

Code:
unsigned int8 Data[16];
unsigned int8 Length;
unsigned int32 result32;

Length = sprintf(Data, "abc");

setup_crc(32, 31, 30, 29, 27, 26, 24, 23, 21, 20, 19, 15, 9, 8, 5);
crc_init(0);
result32 = crc_calc32(Data, Length, 8);

fprintf(PC, "getenv(\"CRC\") returns %u, length of string \"%s\" is %u.\r\n", getenv("CRC"), Data, Length);
fprintf(PC, "HW CRC-32 result from \"abc\" is 0x%08X  (expect 0x352441C2)\r\n", result32);


Result on the console:

Quote:
getenv("CRC") returns 2, length of string "abc" is 3.
HW CRC-32 result from "abc" is 0x6B4B33E0 (expect 0x352441C2)



If I instead initialize with crc_init(0xFFFFFFFF); the result is:

Quote:
getenv("CRC") returns 2, length of string "abc" is 3.
HW CRC-32 result from "abc" is 0xCA0BE10B (expect 0x352441C2)



As you can see, the code is not producing the expected result whether i initialize with 0 or 0xFFFFFFFF.

What am I doing wrong? Any help would be greatly appreciated!
I just want to be able to calculate CRC-32 in hardware of a string of bytes, using the built-in functions of the compiler.

Thanks in advance,
Erik
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Wed Aug 10, 2022 10:04 am     Reply with quote

Your number sequence for the CRC setup does not look right.
0xEDB88320

Should be:

X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5
+X^4+X^2

These are not the factors you are loading in your setup...
opAmp



Joined: 09 Aug 2022
Posts: 4
Location: Norway

View user's profile Send private message

PostPosted: Wed Aug 10, 2022 11:28 am     Reply with quote

Thank you for your suggestion Ttelmah, that is highly appreciated! :-D

I now tried to use this setup:
setup_crc(32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2);

Unfortunately, I still get the wrong results. As usual, I try with crc_init(0xFFFFFFFF) and crc_init(0) since I am not sure which of them is the correct one to use.

I do not understand how this polynomial relates to 0xEDB88320. However, if I add two more coefficients at the end, like this:

setup_crc(32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0);

...then that polynomial is the reverse of 0xEDB88320, i.e. 0x04C11DB7, but with the extra 32nd coefficient in the beginning (making it 0x104C11DB7).

That did not work either. I still have not been able to make the code produce the correct CRC-32 result for the string "abc".

Any other suggestions?
opAmp



Joined: 09 Aug 2022
Posts: 4
Location: Norway

View user's profile Send private message

PostPosted: Wed Aug 10, 2022 7:52 pm     Reply with quote

Wow, I am SO impressed!
I just received an excellent response from Richard at CCS Support. This fully solved my problem.

Here is the email from Richard:

Quote:
The problem is the polynomial you're using is the reversed CRC-32 polynomial. Which the PIC's hardware can't do because that polynomial has the least significant bit set as 0, and the PIC's hardware generator always has the least significant bit of the polynomial set as 1.

What you need to is use the normal CRC-32 polynomial 0x04C11DB7 to do the calculation. To get the reversed CRC-32 result it also requires that the module be initialized to 0xFFFFFFFF, the input data be reflected, which the CRC peripheral can do, the result to be reflected and the result to be XOR'd by 0xFFFFFFFF.

For example the following code will get you the same result as the online calculator you're looking at:

Code:
//Function to reflect the output
unsigned int32 ReflectInt32(unsigned int32 Value) {
   unsigned int16 i;
   unsigned int32 Result = 0;
   
   for(i=0;i<32;i++)
   {
      if(bit_test(Value, i))
         shift_left(&Result, 4, 1);
      else
         shift_left(&Result, 4, 0);
   }
   
   return(Result);
}

//Code in main() to do the CRC calculation
   unsigned int8 Data[16];
   unsigned int8 Length;
   unsigned int32 result32;
   Length = sprintf(Data, "abc");
   setup_crc(CRC_LITTLE_ENDIAN, 32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0);
   crc_init(0xFFFFFFFF);
   result32 = ReflectInt32(crc_calc32(Data, Length, 8)) ^ 0xFFFFFFFF;
   fprintf(PC, "getenv(\"CRC\") returns %u, length of string \"%s\" is %u.\r\n", getenv("CRC"), Data, Length);
   fprintf(PC, "HW CRC-32 result from \"abc\" is 0x%08X  (expect 0x352441C2)\r\n", result32);

I also tested it with a couple other strings to verify that it was giving the same result as online calculator.

Richard
CCS Support

Based on this help, I have now made a little function that does everything for me. It looks like this:

Code:
unsigned int32 crc32(const void *data, int n_bytes)
{
   unsigned int32 result = 0;
   unsigned int32 value;

   setup_crc(CRC_LITTLE_ENDIAN, 32,26,23,22,16,12,11,10,8,7,5,4,2,1,0);
   crc_init(0xFFFFFFFF);
   value = crc_calc32(data, n_bytes, 8);

   for(unsigned int16 k=0; k<32; k++)
   {
      if(bit_test(value, k))
         shift_left(&result, 4, 1);
      else
         shift_left(&result, 4, 0);
   }
   return ~result;
}


Thank you again, Ttelmah, for your help. You were right, the polynomial was not correctly specified.

Case closed.

Erik
PS: Another CRC calculator webpage:
https://crccalc.com/?crc=abc&method=crc32&datatype=ascii&outtype=0
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Wed Aug 10, 2022 11:41 pm     Reply with quote

Brilliant. Well done Richard.
Handling reverse polynomials, was a thing I had to do years ago with CRC16.
Hadn't looked at these for CRC32. Eeek!.
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Thu Aug 11, 2022 4:57 am     Reply with quote

For anyone trying to get their head round this, this site is brilliant:

[url]
https://github.com/Michaelangel007/crc32
[/url]

You can see exactly how this all works. Very Happy
opAmp



Joined: 09 Aug 2022
Posts: 4
Location: Norway

View user's profile Send private message

PostPosted: Tue Aug 16, 2022 7:47 am     Reply with quote

Thank you Ttelmah! Smile
That website explains why I was banging my head against a brick wall when trying to make it work without understanding what I was doing.

So, in summary...
If I understand correctly, for the most popular polynomial (which can be in the normal form 0x04C11DB7 or in the reversed form 0xEDB88320) there are 32 permutations of the various ways to calculate the CRC, and only four of these being valid, meaning that the results are correct/standardized CRC-32 values. Confused

Out of these four standardized ways, only two of them lead to the result that I was looking for: 0x352441C2. The other two, which is another form of CRC-32, gives a different result (not 0x352441C2).

Still there are 28 other ways which produce non-standardized garbage output. I am sure I touched upon most of these when I was hopelessly fiddling with the various parameters Laughing

All of the above is for the most popular CRC-32 polynomial (0x04C11DB7 / 0xEDB88320). But there are several other popular polynomials (e.g. CRC-32C, CRC-32K and CRC-32Q) in use as well.

Yeah... :-D
(I miss the days when we were just XOR-ing some bytes to make a simple checksum, haha! Wink )
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Tue Aug 16, 2022 8:04 am     Reply with quote

Yes, or the old actual 'checksum' (add and just use the low bits of the
result).... Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group