A discussion group for the PICMicro microcontroller. Also called the Microchip PIC, this list is dedicated to the use and abuse of this fine, simple, microcontroller. Close to topic posts are welcome, ie. general electronics.
|
To those of you that are more experienced (than me); I've now started on a bootloader that will eventually transfer the 14KB program into the FLASH memory. I'm thinking of breaking the transfer up into 16 or 32 byte frames. Obviously when the program is finally in the memory every single bit must be correct. So how do you do this? I can see a few ways of integrity check & error handling: A: ask for the frame to be sent 3-4 times, and if all are equal then accept it as valid. (slow but safe). B: checksum validation, resend frame if checksum error. (faster but certain errors may slip trough...unacceptable?) C: CRC, slightly better than checksum. (fast but certain errors may still slip trough...unacceptable?) D: error correcting codes like Hamming, Reed-Solomon, and others (somewhat slow and very complex). I would prefer to go for A and although it is somewhat 'brute force' it is also 100% safe, and most of all it is simple. Unless you have a better idea? -- ******************************************* VISIT MY HOME PAGE: <http://home.online.no/~eikarlse/index.htm> LAST UPDATED: 23/08/2003 ******************************************* Best Regards Eirik Karlsen |
|
|
|
> I can see a few ways of integrity check & error handling: - what bit error rate do you expect? - what chance is acceptable for an erroneous image being accepted as good? (note that a communication protocol that reduces this chance to 0 does not exist) Wouter van Ooijen -- ------------------------------------------- Van Ooijen Technische Informatica: www.voti.nl consultancy, development, PICmicro products |
|
|
|
You should probably consider where errors might occur and data transmission is only one. Another could be degradation of the flash over time. For many years the Intel Hex format has been good enough - the frames are limited to 16 bytes (32 chars) with checksum. Although seldom implemented, you could check for extraneous chars between the CRLF and the next ':'. I suppose you could limit the alpha chars to upper case (that may be an existing condition of most code). Another idea that is commonly used: the code itself runs a CRC of the entire flash every time it starts up. The proper result is usually in the last bytes of the program code. After all, it is the code in memory that needs to be error free! --- In , "Wouter van Ooijen" <wouter@v...> wrote: > > I can see a few ways of integrity check & error handling: > > - what bit error rate do you expect? > - what chance is acceptable for an erroneous image being accepted as > good? (note that a communication protocol that reduces this chance to 0 > does not exist) > > Wouter van Ooijen > > -- ------------------------------------------- > Van Ooijen Technische Informatica: www.voti.nl > consultancy, development, PICmicro products |
|
Can you read the code back and compare to original? --- Eirik Karlsen <> wrote: > To those of you that are more experienced (than me); > I've now started on a bootloader that will eventually transfer the > 14KB program into the FLASH memory. > I'm thinking of breaking the transfer up into 16 or 32 byte frames. > Obviously when the program is finally in the memory every single bit > must be correct. So how do you do this? > > I can see a few ways of integrity check & error handling: > A: ask for the frame to be sent 3-4 times, and if all are equal then > accept it as valid. (slow but safe). > B: checksum validation, resend frame if checksum error. (faster but > certain errors may slip trough...unacceptable?) > C: CRC, slightly better than checksum. (fast but certain errors may > still slip trough...unacceptable?) > D: error correcting codes like Hamming, Reed-Solomon, and others > (somewhat slow and very complex). > > I would prefer to go for A and although it is somewhat 'brute force' > it is also 100% safe, and most of all it is simple. > Unless you have a better idea? > > -- > ******************************************* > VISIT MY HOME PAGE: > <http://home.online.no/~eikarlse/index.htm> > LAST UPDATED: 23/08/2003 > ******************************************* > Best Regards > Eirik Karlsen ===== My software has no bugs. Only undocumented features. __________________________________ |
|
Hi Eirik
There is only one definate solution I have for
you - use crc16 checksums. We use it all the time in industrial comms in Modbus,
Can, DF1 and you find it in most Fieldbusses. I use it all the time to update flash
via these busses and it is 100% reliable. CRC is one of the most (if not the most)
reliable check sums. All our stuff are RTU's in remote areas and we have to have
absolute reliability and it is not that difficult.
There are some ways to get even more reliability
eg. byte to indicate how many data bytes will follow but crc is still the
best
regards
Martin
|
|
|
|
--- In , "martin de lange" <martin_de_lange@x> wrote: > There is only one definate solution I have for you - use crc16 > checksums. We use it all the time in industrial comms in Modbus, > Can, DF1 and you find it in most Fieldbusses. I use it all the > time to update flash via these busses and it is 100% reliable. CRC > is one of the most (if not the most) reliable check sums. All our > stuff are RTU's in remote areas and we have to have absolute > reliability and it is not that difficult. First of all, I agree that CRC is the way to go. But let's be real here -- it is NOT 100% reliable. There are many types of errors which a CRC simply will not detect. If it did work 100% then every download off the internet would be perfect and let's face it, bad downloads do occure occasionally (although rarely). 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.) |
|
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,
|
|
|
|
It's no soooooo complex to implement the CRC... Look at
www.piclist.com and search there for CRC in the source code
archive....
Best Regards
Mauricio D. Jancic
-- |
|
Eirik Karlsen wrote: > 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 ! No, CRC is very very easy. Fast CRC is a little bit more complicated. I can let you have the source for the simple solution written in XCSB if you would like (it's only about 10 lines of code). I don't think the fast version would be worth the overhead of using the required 512 byte table. Regards Sergio Masci http://www.xcprod.com/titan/XCSB - optimising structured PIC BASIC compiler |
|
A checksum simply adds the recieved bytes together, discarding any overflow. It won't catch reversed bytes -- but that's a fairly rare communication hit. A simple checksum will catch many of the typical hits you're likely to find in a short local link. That's why it was so popular in XModem, and in the Intel download format. People use the more robust CRC because it can catch single-bit hits and reversed bytes. Plus, implementing it in hardware is very straightforward. For your application, having the sending program calculate an 8-bit checksum for 32 bytes sent, then sending the checksum so the reciever can verify it, should be sufficient, and would be really fast compared to sending the data three times. --- In , Eirik Karlsen <eikarlse@o...> wrote: > 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 |
|
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;
| |||
|
|
Sergio,
thanks..just send it over so I can have look at it. sergio masci wrote:No, CRC is very very easy. Fast CRC is a little bit more complicated. I can let you have the source for the simple solution written in XCSB if you would
|
|
Scott and others; thanks for your valuable input...looks like I'll be going for a CRC16. This type of code is easily simulated (as opposed to all the real-time motor control stuff in this program), Will try some of your suggestions, simulate, inject some random noise to verify that 'all' errors are trapped. Scott Kellish wrote:-- > ******************************************* > VISIT MY HOME PAGE: > <http://home.online.no/~eikarlse/index.htm> > LAST UPDATED: 23/08/2003 > ******************************************* > Best Regards > Eirik Karlsen |
|
Eirik Karlsen wrote: > Sergio, > thanks..just send it over so I can have look at it. > > sergio masci wrote:No, CRC is very very easy. Fast CRC is a little bit more complicated. I can > > > let you have the source for the simple solution written in XCSB if you would > > like (it's only about 10 lines of code). I don't think the fast version > > would be worth the overhead of using the required 512 byte table. > > > > Regards > > Sergio Masci Here you go, Regards Sergio Masci http://www.xcprod.com/titan/XCSB - optimising structured PIC BASIC compiler const CRCCCITT = 0x1021 proc uint CRC_byte(uint acc, ubyte data) ubyte k ubyte acc2 for k=8 while k>0 step k-=1 do acc2 = acc >> 8 acc = acc << 1 if ((data ^ acc2) & 0x80) != 0 then acc = acc ^ CRCCCITT endif data = data << 1 done return acc endproc |
|
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
|