EmbeddedRelated.com
Forums
Memfault Beyond the Launch

CRC for RS232 communication, F149 and Excel-test

Started by timokirschke September 24, 2008
Hello,

we're using the F149, programmed in C with Crossworks, communicating
via a 115kBd RS232 with the PC.
We implemented a very simple "XOR" CRC, which checks the ASCII
formatted data and is transmitted at the end of the data string, also
ASCII-formatted.

I tried to check, if the CRC calculation is correct, maybe, I did it
a bit stupid.

code (the ASCII formatting is correct, somebody will remember ;) :

u_SendBuf.SendBuf1[43] = 0x0D;
u_SendBuf.SendBuf1[42] = 0x0A;

u_SendBuf.SendBuf1_int[19] = ASCII_HEX_vector_int[SumRHist &
0xFF]; //look up table
u_SendBuf.SendBuf1_int[20] = ASCII_HEX_vector_int[(SumRHist >> 8) &
0xFF];
...
u_SendBuf.SendBuf1_int[1] = ASCII_HEX_vector_int[RTist_O2_left[k0]
& 0xFF];
u_SendBuf.SendBuf1_int[2] = ASCII_HEX_vector_int[(RTist_O2_left
[k0] >> 8) & 0xFF];

// bitwise EXOR for two byte operands
SendCRC = 0;
SendCRC = SendCRC ^ u_SendBuf.SendBuf1[43];
SendCRC = SendCRC ^ u_SendBuf.SendBuf1[42];
...
SendCRC = SendCRC ^ u_SendBuf.SendBuf1[2];

//save CRC via look up table
u_SendBuf.SendBuf1_int[0] = ASCII_HEX_vector_int[SendCRC];
SendBufCnt1 = 43; // counter for bytes to be sent
TXBUF1 = u_SendBuf.SendBuf1[SendBufCnt1]; // load first value into
send buffer

The CRC will become values of 0n and 7n with n={0...F}.
The test in Excel produces values of 0n only, with n differing from
the CRC of the C. This seems to be more correct, because the ASCII
data are bytes {0...F} only, the upper 4 bits remain 0 therefore.
The Excel routine is (sorry, in German):

=BININHEX(WECHSELN(HEXINBIN(value1;8)+HEXINBIN(value2;8);2;0))

Any hint is appreciated, also simplifications.
Thank you in advance!
Best regards, Timo

Beginning Microcontrollers with the MSP430

----- Original Message -----
From: "timokirschke"
To:
Sent: Wednesday, September 24, 2008 11:21 AM
Subject: [msp430] CRC for RS232 communication, F149 and Excel-test
Hello,

we're using the F149, programmed in C with Crossworks, communicating
via a 115kBd RS232 with the PC.
We implemented a very simple "XOR" CRC, which checks the ASCII
formatted data and is transmitted at the end of the data string, also
ASCII-formatted.
Here's a proper CRC that I've used with an ARM application:

//---------------------------- CRC
functions --------------------------------//

u_long crc32_table[256];
/* Initialized first time "crc32()" is called. If you prefer, you can
* statically initialize it at compile time. [Another exercise.]
*/

u_long crc32(u_char *buf, int len)
{
u_char *p;
u_long crc;

if (!crc32_table[1]) /* if not already done, */
init_crc32(); /* build table */
crc = 0xffffffff; /* preload shift register, per CRC-32 spec
*/
for (p = buf; len > 0; ++p, --len)
crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
return ~crc; /* transmit complement, per CRC-32 spec */
}

/*
* Build auxiliary table for parallel byte-at-a-time CRC-32.
*/
#define CRC32_POLY 0x04c11db7 /* AUTODIN II, Ethernet, & FDDI */

init_crc32()
{
int i, j;
u_long c;

for (i = 0; i < 256; ++i) {
for (c = i << 24, j = 8; j > 0; --j)
c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c <<
1);
crc32_table[i] = c;
}
}
Leon
Hi,

I havn't really understood why do you need the look up table, but I
also used the XOR as a checksum in a project in the past.

For the checksum it doesn't matter wether the content is ASCII, Hex
or Octal. You're calculating the XOR sum over bytes.

To simplify it:
SendCRC = 0;
for( int i = 1; i < 44; i++)
{
SendCRC ^= u_SendBuf.SendBuf1[ i];
}
u_SendBuf.SendBuf1[0] = SendCRC;

In your example, the CRC is transmitted at the beginning of the
stream not at the end.
The receiver can simple do XOR over all byte and the sum must be
null, so that the received stream is correct.

Servas,
Stefan

--- In m..., "timokirschke"
wrote:
>
> Hello,
>
> we're using the F149, programmed in C with Crossworks,
communicating
> via a 115kBd RS232 with the PC.
> We implemented a very simple "XOR" CRC, which checks the ASCII
> formatted data and is transmitted at the end of the data string,
also
> ASCII-formatted.
>
> I tried to check, if the CRC calculation is correct, maybe, I did
it
> a bit stupid.
>
> code (the ASCII formatting is correct, somebody will remember ;) :
>
> u_SendBuf.SendBuf1[43] = 0x0D;
> u_SendBuf.SendBuf1[42] = 0x0A;
>
> u_SendBuf.SendBuf1_int[19] = ASCII_HEX_vector_int[SumRHist &
> 0xFF]; //look up table
> u_SendBuf.SendBuf1_int[20] = ASCII_HEX_vector_int[(SumRHist >> 8)
&
> 0xFF];
> ...
> u_SendBuf.SendBuf1_int[1] = ASCII_HEX_vector_int[RTist_O2_left
[k0]
> & 0xFF];
> u_SendBuf.SendBuf1_int[2] = ASCII_HEX_vector_int[(RTist_O2_left
> [k0] >> 8) & 0xFF];
>
> // bitwise EXOR for two byte operands
> SendCRC = 0;
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[43];
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[42];
> ...
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[2];
>
> //save CRC via look up table
> u_SendBuf.SendBuf1_int[0] = ASCII_HEX_vector_int[SendCRC];
> SendBufCnt1 = 43; // counter for bytes to be sent
> TXBUF1 = u_SendBuf.SendBuf1[SendBufCnt1]; // load first value
into
> send buffer
>
> The CRC will become values of 0n and 7n with n={0...F}.
> The test in Excel produces values of 0n only, with n differing from
> the CRC of the C. This seems to be more correct, because the ASCII
> data are bytes {0...F} only, the upper 4 bits remain 0 therefore.
> The Excel routine is (sorry, in German):
>
> =BININHEX(WECHSELN(HEXINBIN(value1;8)+HEXINBIN(value2;8);2;0))
>
> Any hint is appreciated, also simplifications.
> Thank you in advance!
> Best regards, Timo
>

Modbus uses a 16 bit CRC at the end of the message. It has quite good
documentation on generation of the CRC both through a software
implementation of the shift registers or as a look up table (with the
code in C)

Look from page 39 at
http://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf

-Aubrey
And here is a good article about CRC that was in Embedded Programming back in 2000 with C source code.

http://www.netrino.com/Embedded-Systems/How-To/CRC-Calculation-C-Code

C.

----- Original Message ----
From: antedeluvian51
To: m...
Sent: Wednesday, September 24, 2008 1:39:50 PM
Subject: [msp430] Re: CRC for RS232 communication, F149 and Excel-test
Modbus uses a 16 bit CRC at the end of the message. It has quite good
documentation on generation of the CRC both through a software
implementation of the shift registers or as a look up table (with the
code in C)

Look from page 39 at
http://modbus. org/docs/ Modbus_over_ serial_line_ V1_02.pdf

-Aubrey


IAR has a great feature (others may as well) where the flash memory
CRC can be calculated and stuffed into the codespace. At runtime, you
can calculate the CRC and make sure that nothing is corrupted. (The
linker calculates the CRC, so you don't need to do any kind of manual
calculations and filling-memory each build.)

To make things nicer, they give you source code for the CRC
calculations, both a "fast" (table) and "slow" (repeated calcs) way.

Take a look at their app note and code, "Technical Note 91733,
Checksum calculation with XLINK"
http://supp.iar.com/Support/?note=91733&from=search+result

There are a lot of online CRC calculators, too. I like to use this one:
http://www.zorc.breitbandkatze.de/crc.html
as a code verification.

There has been some discussion about why bothering to use a table, and
not just calculate the constants on-the-fly. It may seem fast enough,
but you may calculating CRCs on real-time serial data. At a
reasonable bit/message rate, these times may become important.

Good luck.

Stuart
--- In m..., "timokirschke" wrote:
>
> Hello,
>
> we're using the F149, programmed in C with Crossworks, communicating
> via a 115kBd RS232 with the PC.
> We implemented a very simple "XOR" CRC, which checks the ASCII
> formatted data and is transmitted at the end of the data string, also
> ASCII-formatted.
>
> I tried to check, if the CRC calculation is correct, maybe, I did it
> a bit stupid.
>
> code (the ASCII formatting is correct, somebody will remember ;) :
>
> u_SendBuf.SendBuf1[43] = 0x0D;
> u_SendBuf.SendBuf1[42] = 0x0A;
>
> u_SendBuf.SendBuf1_int[19] = ASCII_HEX_vector_int[SumRHist &
> 0xFF]; //look up table
> u_SendBuf.SendBuf1_int[20] = ASCII_HEX_vector_int[(SumRHist >> 8) &
> 0xFF];
> ...
> u_SendBuf.SendBuf1_int[1] = ASCII_HEX_vector_int[RTist_O2_left[k0]
> & 0xFF];
> u_SendBuf.SendBuf1_int[2] = ASCII_HEX_vector_int[(RTist_O2_left
> [k0] >> 8) & 0xFF];
>
> // bitwise EXOR for two byte operands
> SendCRC = 0;
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[43];
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[42];
> ...
> SendCRC = SendCRC ^ u_SendBuf.SendBuf1[2];
>
> //save CRC via look up table
> u_SendBuf.SendBuf1_int[0] = ASCII_HEX_vector_int[SendCRC];
> SendBufCnt1 = 43; // counter for bytes to be sent
> TXBUF1 = u_SendBuf.SendBuf1[SendBufCnt1]; // load first value into
> send buffer
>
> The CRC will become values of 0n and 7n with n={0...F}.
> The test in Excel produces values of 0n only, with n differing from
> the CRC of the C. This seems to be more correct, because the ASCII
> data are bytes {0...F} only, the upper 4 bits remain 0 therefore.
> The Excel routine is (sorry, in German):
>
> =BININHEX(WECHSELN(HEXINBIN(value1;8)+HEXINBIN(value2;8);2;0))
>
> Any hint is appreciated, also simplifications.
> Thank you in advance!
> Best regards, Timo
>

Good Morning,

many thanks to all, what a lot of help, great! Both, the explanations and
the code examples are very welcome.

What I understood first, is the hidden message, that I did not do a
meaningful or safe CRC calculation. A hint for my laziness? ;)
What I forgot to say, the application is time critical: the MSP is busy
for 980+ us in a 1ms cycle while its control tasks. There is no time left
over. Therefore the CRC loop is splitted into separated commands, it saves
~20us. And yes I know, that this utilisation is too much for the
processor, normally. I have to check the non-overlapping cycles after
every code change using a scope.
That is the reason, why we use tables for ASCII-translation, Stefan. I
discussed it here some weeks ago.

For this reason it will be not possible in this time, to implement a full
CRC algorithm, whether using tables or not. Later we switch to the F2618,
this may allow for the better version.

In the mean time I checked the CRC-calculation of two data records by
hand, it seems to be correct. So the error should be on the PC side (what
the responsible guy does not want to hear).

Weird: in my setup I would not need any CRC, because the communication
between MSP and PC is flawless. Only the colleagues and especially the
partners, using the device hundreds of kilometers away, tell us of the
communication errors. Does anybody know this effect? ;)
Okay, I will check the cabling, especially the grounding.

Thank you again!
Best regards, Timo
There is one CRC implementation for the
ITU-T polynomial: G_16(x) = x^16 + x^12 + x^5 + 1
pointed out by Paul Curtis earlier on this mailing list:

uint16_t crcByte(uint16_t crc, uint8_t b) {
crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= b;
crc ^= (uint8_t)(crc & 0xff) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xff) << 5;
return crc;
}

This takes only twice the time of the table implementation and is much
smaller in flash. The polynomial is also a pretty good one in terms of
error detection capabilities.

I recommend to always use a CRC for communication, this allows you to
recover (on the PC side) from synchronization problems like a reset of
the MSP in the middle of a message transmission. But in general you are
right: communication from MSP to PC is flawless.

Best, Andreas

Am Donnerstag, den 25.09.2008, 07:30 +0000 schrieb timokirschke:
> Good Morning,
>
> many thanks to all, what a lot of help, great! Both, the explanations
> and
> the code examples are very welcome.
>
> What I understood first, is the hidden message, that I did not do a
> meaningful or safe CRC calculation. A hint for my laziness? ;)
> What I forgot to say, the application is time critical: the MSP is
> busy
> for 980+ us in a 1ms cycle while its control tasks. There is no time
> left
> over. Therefore the CRC loop is splitted into separated commands, it
> saves
> ~20us. And yes I know, that this utilisation is too much for the
> processor, normally. I have to check the non-overlapping cycles after
> every code change using a scope.
> That is the reason, why we use tables for ASCII-translation, Stefan.
> I
> discussed it here some weeks ago.
>
> For this reason it will be not possible in this time, to implement a
> full
> CRC algorithm, whether using tables or not. Later we switch to the
> F2618,
> this may allow for the better version.
>
> In the mean time I checked the CRC-calculation of two data records by
> hand, it seems to be correct. So the error should be on the PC side
> (what
> the responsible guy does not want to hear).
>
> Weird: in my setup I would not need any CRC, because the
> communication
> between MSP and PC is flawless. Only the colleagues and especially
> the
> partners, using the device hundreds of kilometers away, tell us of
> the
> communication errors. Does anybody know this effect? ;)
> Okay, I will check the cabling, especially the grounding.
>
> Thank you again!
> Best regards, Timo
>
Look at using the F5x devices (TI have just released them). They are
cheaper than the F2618 and F149 and have a hardware CRC generator. You just
write the data to be CRC'd into the register and out comes the result. I
use it for Flash checksumming - no problems at all.

Ian

2008/9/25 timokirschke

> Good Morning,
>
> many thanks to all, what a lot of help, great! Both, the explanations and
> the code examples are very welcome.
>
> What I understood first, is the hidden message, that I did not do a
> meaningful or safe CRC calculation. A hint for my laziness? ;)
> What I forgot to say, the application is time critical: the MSP is busy
> for 980+ us in a 1ms cycle while its control tasks. There is no time left
> over. Therefore the CRC loop is splitted into separated commands, it saves
> ~20us. And yes I know, that this utilisation is too much for the
> processor, normally. I have to check the non-overlapping cycles after
> every code change using a scope.
> That is the reason, why we use tables for ASCII-translation, Stefan. I
> discussed it here some weeks ago.
>
> For this reason it will be not possible in this time, to implement a full
> CRC algorithm, whether using tables or not. Later we switch to the F2618,
> this may allow for the better version.
>
> In the mean time I checked the CRC-calculation of two data records by
> hand, it seems to be correct. So the error should be on the PC side (what
> the responsible guy does not want to hear).
>
> Weird: in my setup I would not need any CRC, because the communication
> between MSP and PC is flawless. Only the colleagues and especially the
> partners, using the device hundreds of kilometers away, tell us of the
> communication errors. Does anybody know this effect? ;)
> Okay, I will check the cabling, especially the grounding.
>
> Thank you again!
> Best regards, Timo
>
--- In m..., "Ian Okey" wrote:
Hello,
>
> Look at using the F5x devices (TI have just released them). They are
> cheaper than the F2618 and F149 and have a hardware CRC generator. You
just
> write the data to be CRC'd into the register and out comes the result. I
> use it for Flash checksumming - no problems at all.
>
> Ian

interesting, I didn't get it from the last conference. It is definitely
worth to think about.
The F2618 'solution' is an intermediate workaround only. It does not need
any hardware modification, but allows lots of software improvements.

Thanks also to Andreas (and Paul) for the additional algorithm,
Timo

Memfault Beyond the Launch