CRC problem in communication between PC and microcontroller

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use the RS232 to communicate between the atmega8535 microcontroller and the PC. Because an RS232 is very vulnerable to EMI, I added a checksum using the CRC-CCITT function in the CRC16.h file from the AVR-libc library.
To be able to communicate, the microcontroller and the PC must calculate the CRC-checksum exactly the same way. I implemented the crc-ccitt algorithm in C given in the avr-libc documentation in Java, but is doesn't work. I doubt if it even works in C. So for people who encounter the same problem, I give my WORKING java-code-snippet here:

    byte a,c,k,h;
    a=(byte)(((CRC_value&0x00FF)) ^ data);
    c=(byte)((a<<4) ^ a);
    k=(byte)(((c<<3)) ^ (CRC_value>>8) ^ ((c&0xFF)>>4));
    h=(byte)(c ^ ((c&0xFF)>>5));
    CRC_value=(char)((((char)h)<<8)|(k&0xFF));

:wink:

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A shot in the dark: did you make sure your endianness was correct?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The problem comes in when shifting a byte in Java a nibble to the right. In Java, byte values are always between -128 and +127. So e.g. 0xA2 in Java is a negative number and when shifting it a nibble to the right it becomes 0xFA.
The assembly CRC algorithm of the AVR does a nibble shift to the right by swapping the nibbles and then AND'ing the result with 0x0F. So in our example 0xA2 would become 0x0A and this is obviously not the same as the 0xFA value in Java. I then changed my Java program to take this problem into account.

I'm not sure if this problem also occurs in C-language. Maybe it depends on the compiler used. I think the typecasting signs shown in the AVR-libC documentation are meant to prevent problems of this kind.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

In C the right shift operation (operator '>>') depends on the signed/unsigned attribute of the data type to be shifted. On unsigned data types the operation is a logical shift (inserting zeroes at the MSBs). Working with signed data types the operation is an arithmetic shift (inserting a copy of the sign bit at the MSBs).

In Java there is an arithmetic shift right operator ('>>') and a logical shift right operator ('>>>'). You can use the last one for your purposes.

Regards,

Carlos.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

carloslamas wrote:

In C the right shift operation (operator '>>') depends on the signed/unsigned attribute of the data type to be shifted. On unsigned data types the operation is a logical shift (inserting zeroes at the MSBs). Working with signed data types the operation is an arithmetic shift (inserting a copy of the sign bit at the MSBs).

Actually the C standard does not require the above. The draft version of the C99 standard available at http://www.open-std.org/jtc1/sc22/open/n2794/n2794.pdf
states that:

"The result of E1 >> E2 is E1 right-shifted E2 bit positions. ... If E1 has a signed type and a negative value, the resulting value is implementation-defined."

The behaviour must therefore be checked with different architectures.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your post LieBtrau,

You helped me out of a confusing situation. Dunno if it's of use to anyone, but herewith your code, modified for C++ - trailed and tested, it matches the crc-ccitt implementation WinAVR.

  
unsigned char a,b,c,d;
a = (unsigned char)((crc & 0x00FF) ^ data);
b = (unsigned char)((a << 4) ^ a);
c = (unsigned char)((b << 3) ^ (crc >> 8) ^ ((b & 0xFF) >> 4));
d = (unsigned char)(b ^ ((b & 0xFF) >> 5));
crc = (unsigned int)(((unsigned int)d << 8)|(c & 0xFF));

"A leader is not one with the most followers, but one who creates the most leaders."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Antonv,

what was wrong with equivalent function crc_ccitt_update from avr-libc Reference Manual?
BTW, I mistrust also about this function because some time ago I was trying to use it but I have find out following problem.

For example if I have message 0xAA 0xBB 0xCC and I append computed CRC as follows: 0xAA 0xBB 0xCC CRC(HI) CRC(LO) than if no error occur after computing CRC of the whole message I have to get result 0x00. But I did not. Did you find same problem or was I doing something wrong?

Roman

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am also confused by crc_ccitt_update(). It doesn't seem to give the correct result for the string "123456789" which I think is 0xe5cc, I get 09b74.

I have searched the internet and there seem to be a lot of confusion about CRC-CCITT (and other types of CRC as well).

Has anyone used crc_ccitt_update() to communicate with equiment using CRC-CCITT?

Have I got everything wrong?

/Janne

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello lillahuset,

I have made an application on a ATMEGA8535 that communicates with a PC using the RS232. The program on the PC is written in Java. I had troubles too when using the CRC-checksum of the AVR-LibC documentation. The problems in the CRC-calculation are the shift operations. The microcontroller performs them in a different way than the PC. More info can be found on my previous reply.
The best way to analyze this problem is to calculate the CRC of one character instead of ten and then manually go through the algorithms step by step. The algorithm in your microcontroller can be found by examining the assembly code listing. This is the file with extension *.lst of your project.

Have fun.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks a lot for the C code snippet.
Thats is exactly what I need for my new AVR project, where
I have a RF link from the PC to an Atmel.

Cheers
Rubi

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lillahuset wrote:
I am also confused by crc_ccitt_update(). It doesn't seem to give the correct result for the string "123456789" which I think is 0xe5cc, I get 09b74.

I have searched the internet and there seem to be a lot of confusion about CRC-CCITT (and other types of CRC as well).

Has anyone used crc_ccitt_update() to communicate with equiment using CRC-CCITT?

Have I got everything wrong?

/Janne

I've got the same problem. The result of the AVR CCITT implementation can't be compared to any of the calculations I found on the internet. The calculations I found are all returning 0xE5CC or 0x29B1. The differences between these answers must be found in augmenting the message with zero's.
So I've implementated the 'right' function according to this page: http://www.joegeluso.com/softwar...

But on the other hand if you implement the AVR implementation on both machines there is no problem at all.