Parallax RF Transceiver object using polynomial CRC method to reduce Data Error
Beau Schwabe
Posts: 6,566
Updated latest version here
This is in the early stages, but I wanted to put a CRC object together that provided a little bit stronger
error detection than just addition or XORing each data byte on top of the adjacent neighbour. So I've put together a CRC engine that uses polynomials written in Propeller assembly. Once you tell it the size of the packet and where the Data is as well as the Polynomial key it will automatically update a CRC result that can be appended to your data transmission. On the receive end, if you have the same Polynomial CRC Driver running you must use the same Polynomial key. By comparing the Received CRC value verses the locally calculated CRC value, you can determine if a data packet is valid or not.
The main CORE program is called 'CRC_polynomial.Spin' ... There are a couple of example RX and TX programs that use the RF Transceivers, they still need some work but get the idea across. The main program to try to incorporate and use is the 'CRC_polynomial.Spin' file.
What is CRC anyway? A CRC is an error-detecting code. It stands for cyclic redundancy check and there are many forms of CRC. Some have very weak error detecting abilities while others have very strong error detecting abilities. An example of a week error detection scheme would be the use of the Parity bit in serial transmission. In this form The Parity simply represents the total number of Bits indicating if they are ODD or EVEN. Another approach is simply to ADD all of the data bytes together and look at the LSB 8-Bits of the result. With each of the approaches mentioned, the error detecting gradually gets better and better, you still can't beat polynomial division when it comes to CRC. The computation resembles a long division operation in which the quotient is discarded and the remainder becomes the result, with the important distinction that the arithmetic used is the carry-less arithmetic.
Example:
Edit: Files updated on 11-05-2009
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/7/2010 8:42:02 PM GMT
This is in the early stages, but I wanted to put a CRC object together that provided a little bit stronger
error detection than just addition or XORing each data byte on top of the adjacent neighbour. So I've put together a CRC engine that uses polynomials written in Propeller assembly. Once you tell it the size of the packet and where the Data is as well as the Polynomial key it will automatically update a CRC result that can be appended to your data transmission. On the receive end, if you have the same Polynomial CRC Driver running you must use the same Polynomial key. By comparing the Received CRC value verses the locally calculated CRC value, you can determine if a data packet is valid or not.
The main CORE program is called 'CRC_polynomial.Spin' ... There are a couple of example RX and TX programs that use the RF Transceivers, they still need some work but get the idea across. The main program to try to incorporate and use is the 'CRC_polynomial.Spin' file.
What is CRC anyway? A CRC is an error-detecting code. It stands for cyclic redundancy check and there are many forms of CRC. Some have very weak error detecting abilities while others have very strong error detecting abilities. An example of a week error detection scheme would be the use of the Parity bit in serial transmission. In this form The Parity simply represents the total number of Bits indicating if they are ODD or EVEN. Another approach is simply to ADD all of the data bytes together and look at the LSB 8-Bits of the result. With each of the approaches mentioned, the error detecting gradually gets better and better, you still can't beat polynomial division when it comes to CRC. The computation resembles a long division operation in which the quotient is discarded and the remainder becomes the result, with the important distinction that the arithmetic used is the carry-less arithmetic.
Example:
Polynomial (Must match the sender as well as the receiver) │  10101100 <-- quotient (discarded we don't care what this value is) _______________ 11011 ) 111001010000 <-- dividend (The DATA) 11011 ----- 1111010000 11011 ----- 10110000 11011 ----- 1101000 11011 ----- 100 <-- CRC (remainder or what we append to the data sent)
Edit: Files updated on 11-05-2009
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/7/2010 8:42:02 PM GMT
Comments
Here is the SPIN version of the CORE program before I converted it to Spin so you can get a better idea of what the Propeller assembly is doing...
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Then you can hardcode the summation of bits like:
.... oh .... now I understand ... it does not give you the number of bits, but the position of the highest bit. Anyway ... BitCount is called several times, so it would be good to optimize.
That sounds like a binary search would be helpful as for searching in·32 items·it only needs 5 steps.
I think number of bits is correct, it's not the number of bits that are "1", it's the total minimal number of bits required to represent the number.
Anyway, yes, I think a lookup table would work here, and there's probably a simple formula that could be applied that I just haven't messed with in detail yet instead of the iterative process I'm currently using.
The main thing I was looking for was functionality with the idea in mind that the bandwidth of the RF is limited to about 10kBits/sec. With that in mind there is plenty of overhead when calculating the CRC value.
Edit...
This code reduces the iteration loop from 20 clocks to 12 clocks almost in half
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 11/4/2009 10:32:23 PM GMT
Revision History:
Version 1.0.a - (10-30-2009) original file created
Version 1.0.b - (11-04-2009) improved bit width routine
Version 1.0.c - (11-05-2009) optimized flow of long division routine
MagIO2,
I have been thinking, and I'm not sure that a lookup table would help much since the BitWidth could technically be close to 16 Bits wide and higher as I change the program to allow polynomial keys wider than 16 Bits.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
You've probably been down the CRC16 table road, but it is worth mentioning.
Here's a link to my table driven CCITT CRC16 Spin code. The table used is 512 bytes.
http://forums.parallax.com/showthread.php?p=800272
Of course CRC also has limits. CRC16 can have duplicate results for < 1000 byte packets.
For packets > 1000 bytes, CRC32 should be considered.
Wikipedia has a good article on CRC en.wikipedia.org/wiki/Cyclic_redundancy_check
Cheers.
Post Edited (jazzed) : 11/5/2009 10:52:11 AM GMT
I looked at your code, but I don't see the same polynomial listed here
wikipedia shows that for CRC16 CCITT that the polynomial should be...
I would be curious to compare the result of your CRC program with the program that I am running against the same 512 Byte data packet.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 11/5/2009 6:22:14 PM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
My Prop Info&Apps: ·http://www.rayslogic.com/propeller/propeller.htm
The one in my code is CRC-CCITT. Using CRC16 poly instead works too.
You can test your results here to see if the CRC is as expected.
Ok, I understand there are several different polynomial forms that can be used (even called the same thing). Which helps the confusion factor.
Thanks for the link
I'm still trying to figure out how 0x1021 equates to ---> x16 + x12 + x5 + 1
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 11/5/2009 6:18:33 PM GMT
Post Edited (jazzed) : 11/5/2009 6:28:11 PM GMT
I had to lay down a few basic principles and a few of them evolved in order to decide what the most logical approach to this would be. Some priority obligations have limited my output on this but I hope to have something very soon. The basic building blocks are mostly in play, they just need to be pieced together. Included is a flow diagram of how I think things should happen, and I've posted it in a few other locations and haven't had anybody knock it down >yet< as to some fundamental thing I might be overlooking, so for now I will use it as the code template for how it's going to work. Perhaps a future implementation would be bi-directional Full-duplex in continuous mode.
Basically there are two modes: Normal and continuous
TX side:
- Will send the data you place in a buffer and append the CRC when you issue a SEND command (who da thunk?)
- A small amount of handshaking will transpire and the TX unit will keep sending the data packet until an acknowledgement has been received or until a number of user set retries have expired.
- If an acknowledgement is received and the TX unit is in continuous mode it just starts all over again, otherwise the TX command has completed.
RX side:
- As data is received it goes into one of two buffers (two buffers explained later) If the received CRC does not match the locally calculated CRC, the receiver goes into a wait for sync loop (beginning of Flow)... This in turn generates a timeout on the TX side so that hopefully the packet will be re-transmitted.
- If the CRC is valid, the RX module goes into TX mode and sends an acknowledgement to the TX unit which 'should' be waiting in receive mode for the acknowledgement.
- If the RX unit is in continuous mode it will return to the beginning of the flow where it will wait for the next incoming SYNC signal, otherwise the RX command has completed.
Note:
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 11/13/2009 8:10:09 AM GMT
Best Regards, David
I tried to implement a Half Duplex mode with acknowledgement from the receiver to verify that Data had been received and was valid, but the RF Transceivers have problems switching modes mid stream from a Transmitter to a Receiver and then back to a Transmitter. By the time they re-negotiate it ends up being incredibly slow. In practice, with the CRC applied and the double buffering on the receiver, I have not received any data errors with any of the data that does get through.
What you can do (left for the user to exercise) is to send packets in burst mode from point A to point B and then reverse the direction.
The Code has been reduced to simple Send, Receive, Put, and Get commands. You basically just treat the Put and Get like an address "on the other end". Both Send and Receive update from one database to the other database via the Transceivers.
As always, please provide feedback where applicable, and I will post this object to the OBEX after a trial period.
Enjoy!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 11/19/2009 5:19:52 AM GMT
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 4/27/2010 4:44:32 AM GMT
I'd like to do this for streaming ADC readings over USB using an FTDI chip (using either VCP or D2XX driver)