I have used the following for several
years on a variety of Modbus systems. It works fine on 20mhz xtal for up
to 56k. Bear in mind going any faster might need table lookups and not
calcs. Modbus use the TTY version of CRC checking.
Initialise with this before
use
movlw 0xFF
movwf CRC_Low
movwf CRC_High
add to the checksum with this
movfp ModbusBuffer1,WREG
call CallAddCRC16M
;call for every byte in
packet that is tx'ed except the crc bytes
obviously the results in CRC_High and
CRC_Low that is calculated on the fly as it comes in is then compared with
the last two bytes in the packet that is the crc.
;-------------------------
; ****************************** CRC16 routine
******************************************
;-------------------------
;--CLASS REGISTERS-----------------------
;Temp1
;CRC_High
;CRC_Low
;----
CallAddCRC16M
xorwf CRC_High,f
movlw 8
movwf Temp1
CRC_Loop
bcf ALUSTA,C
rrcf CRC_Low,f
rrcf CRC_High,f
btfss ALUSTA,C
goto NoXOring
movlw B'10100000'
xorwf CRC_Low,f
movlw B'0000001'
xorwf CRC_High,f
NoXOring
decfsz Temp1,F
goto CRC_Loop
return
----- Original Message -----
From: Scott Kellish
To: p...@yahoogroups.com
Sent: Tuesday, February 17, 2004 9:11 AM
Subject: Re: [piclist] Re: CRC / CHKSUM
Hi Karl,
Here is the code I use. I downloaded the
assembly (PIC side) code and a article (pdf attached) from EDN
maginzine's website a couple of years ago and wrote the pascal code (PC
side) from the article. On the PC side I assemble the message and then calculate
the CRC over it. On the PIC side, I calc the CRC as I receive each byte. One
nice feature is that since the complement of the CRC is stored in the
message, on the PIC side when you include the 2 CRC bytes included in the
received message, if the message was received correctly, your resulting CRC will
be zero so you don't have to do a 2 byte comparision at the
end.
You''ll have to tailor the PIC code
to your message format. It written specifically for mine which is formated
as:
<SOH> <NODEID> <MSGLEN>
<CMD> <DATA1>..<<DATAn> <CRC1>
<CRC2>
I use this between the PC and a device with 2
16F628 PIC's and between the 2 PICs on the board. Works great.
Scott Kellish
SoftSystem Solutions
s...@comcast.net
PIC Code:
;********************************************************************
;
; CRC-16 (x^16+x^15+x^2+x^0)
; No tables, No loops, No
temporary registers used.
;
; Input: W = Data byte for CRC
calculation
;
crc_hi:_CRC_LO 16 bit CRC register
;
; Output: crc_hi:_CRC_LO
updated.
;
; Notes: CARRY is trashed.
; DIGIT CARRY is trashed.
; ZERO is trashed.
; W is zero on exit.
;
;********************************************************************
; This will calculate a 16bit CRC and store the
results as the last two bytes of the message
;
CALC_CRC16 MOVLW 2
CALL PROC_CRC16
MOVF CRC_HI,
W
XORLW -1
MOVWF INDF
INCF FSR, F
MOVF _CRC_LO, W
XORLW -1
MOVWF INDF
RETURN
; This will calculate a 16-bit CRC for a message,
including the 2 passed CRC bytes.
; Returns Z = 0 if Message received
incorrectly
; Z
= 1 if Message OK
;
CHK_CRC16 MOVLW 4
CALL PROC_CRC16
MOVLW HIGH CRC_CHECK
SUBWF _CRC_HI, W
BNZ
CHK_CRC16A
; CRC MS wrong, ignore message
MOVLW LOW CRC_CHECK
SUBWF _CRC_LO, W
CHK_CRC16A RETURN
;
PROC_CRC16 ADDWF IOBUF_LEN, W
MOVWF _MSGLEN
MOVLW HIGH
CRC_INIT ; SINCE
<SOH> IS PRESENT AND CONSTANT IN EACH MSG
MOVWF
_CRC_HI
; INIT CRC WITH <SOH> CRC VALUE INSTEAD OF RUNNING
MOVLW LOW
CRC_INIT
; THROUGH CALCULATION
MOVWF _CRC_LO
MOVLW IOBUF_ADDR
MOVWF FSR
BTFSS _SysState,
_SysStateBroadcastMsg
B
PROC_CRC16A
INCF _MSGLEN,
F
DECF FSR, F
MOVLW 0FFH
B
PROC_CRC16B
PROC_CRC16A MOVF INDF, W
PROC_CRC16B MOVWF _CRC_TMP0
; STORE DATA
IN TEMPORARY REGISTER
MOVLW
B'00001000' ;
SET COUNTER FOR 8 DATA BITS
MOVWF
_CRC_TMP2 ;
LOAD COUNTER REGISTER
MORE_ROTATES
CLRWDT
MOVF _CRC_TMP0,
W ; MOVE BUFFERED
DATA TO 2ND BUFFER
MOVWF
_CRC_TMP1 ;
THIS REGISTER IS CORRUPTED WITH EVERY PASS
MOVF _CRC_HI,
W ; MOVE UPPER
SHIFT REGISTER TO WORKING REG.
XORWF _CRC_TMP1,
F ; XOR SHIFT
REGISTER WITH DATA REGISTER
BTFSS
_CRC_TMP1,7 ;
MSB IS XOR OF STAGE16 AND INPUT DATA BIT
B
NO_XORWF ;
IF BIT IS CLEAR THEN NO COMPLEMENT OF STAGE2,15
MOVLW
B'00000010' ;
PREPARE TO COMPLEMENT STAGE2
XORWF _CRC_LO,
F ; COMPLEMENT
STAGE2 OF SHIFT REGISTER
MOVLW
B'01000000' ;
PREPARE TO COMPLEMENT STAGE15
XORWF _CRC_HI,
F ; COMPLEMENT
STAGE15 OF SHIFT REGISTER
NO_XORWF RLF
_CRC_TMP0,F ;
ROTATE NEXT DATA BIT INTO POSITION
RLF
_CRC_TMP1,F ;
ROTATE XOR OF INPUT INTO CRC16_LO
RLF _CRC_LO,
F ; SHIFT CRC16
REGISTER
RLF _CRC_HI,
F ; SHIFT CRC16
REGISTER
DECFSZ _CRC_TMP2,
F ; COUNT OUT 8 DATA
BITS
B
MORE_ROTATES ; NOT
FINISHED WITH THIS DATA BYTE
INCF FSR, F
DECFSZ _MSGLEN, F
B PROC_CRC16A
RETURN
endasm
function TRIOPMessage.CalcCRC16(UseTxBuffer:
Boolean): Boolean;
var
Buf: PByteArray;
Cnt:
Integer;
CRC16: WORD;
i: Integer;
procedure
AddCRC16(const c: byte);
var
crc: Word;
begin
crc := CRC16;
asm
mov dx, crc
mov al, c
mov ecx, 8
@MoreRotates:
mov ah, al
xor ah, dh
test ah,
128
jz @NoXor
xor dx, $4002
@NoXor:
CLC
rcl ax, 1
rcl dx, 1
loop @MoreRotates
mov crc, dx
end;
CRC16 := crc;
end;
begin
if
UseTxBuffer then
begin
Buf := FTxBuf;
Cnt := FTxCnt;
end
else
begin
Buf := FRxBuf;
Cnt := FRxCnt;
end;
CRC16 := $0000;
i := 0;
while i
<= Cnt-2-1 do // Iterate
begin
AddCRC16(Buf[i]);
Inc(i);
end;
CRC16 := not CRC16;
if UseTxBuffer then
begin
Buf[i] := Hi(CRC16);
Buf[i+1] := Lo(CRC16);
Result := True
end
else
Result := ((Buf[i] = Hi(CRC16)) and (Buf[i+1] = Lo(CRC16)));
end;
----- Original Message -----
From: Eirik Karlsen
To: p...@yahoogroups.com
Sent: Monday, February 16, 2004 1:04 PM
Subject: Re: [piclist] Re: CRC / CHKSUM
Hi,
Well....I'd like to avoid crc because of its
complexity (and I've never used it before).
And I won't even
touch MD5 for the same reason.
Apart from this I've got only 2KB
memory left for the entire bootloader.
MD5 and CRC tried to get max
performance with minimal extra 'formatting', but for downloading
14KB over a 2meter RS232 cable into a pic the speed is of little importance...
I'm willing to wait a few extra sec's. So how about
transmitting a 32byte frame 2-3 times, receiver compares those and if all are
equal accept,
else start a new frame transmission.
And what are the
odds of getting 1 or 2 'bad bits'.....same bits, same location,
in 3 consecutive 32byte frames?
I dunno....must be 1 in fantazillions !
If
you want the maximum reliability you would go with a MD5 checksum
but it is a much heavier algorithm and I don't think you would
want
to do that in a PIC. Even MD5 is not 100% but it is so
good that
statistically it is. (The odds of an error that
isn't caught is
something on the order of 1 in
billions.)
--
*******************************************
VISIT MY
HOME PAGE:
<http://home.online.no/~eikarlse/index.htm>
LAST
UPDATED: 23/08/2003
*******************************************
Best
Regards
Eirik Karlsen
to unsubscribe, go to
http://www.yahoogroups.com and follow the instructions
to
unsubscribe, go to http://www.yahoogroups.com and follow the
instructions