|
|
View previous topic :: View next topic |
Author |
Message |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
CRC8 (Dallas 1-wire) |
Posted: Wed Mar 08, 2006 8:11 am |
|
|
It is already hidden in the forum somewhere, but I like this efficient implementation of a CRC8 algorithm so much I thought it best to post it here as well.
Code: | //-----------------------------------------------------------------------------
// Calculate crc8 checksum
// This is the checksum as used in the Dallas One Wire protocol.
// Advantage of this checksum over other crc's is that because of a pecularity
// of this specific polynomial it allows bytewise processing without bit
// shifting. It's very fast, small and uses no RAM.
//
// Based on: Maxim Application Note 27,
// http://www.maxim-ic.com/appnotes.cfm/appnote_number/542
// Original C code: T. Scott Dattalo
// http://www.dattalo.com/technical/software/pic/crc_8bit.c
// Optimized by: Dirk Van den Berge (dvdb)
// donated to the CCS-forum 12-jan-2004
// http://www.ccsinfo.com/forum/viewtopic.php?t=17170
//-----------------------------------------------------------------------------
int8 Calc_Crc8(int8 *Buffer, int8 byte_cntr)
{
int8 crc=0;
#ASM
//copy pointer to pointer register (CCS doesn't support lfsr assembly instruction)
movff Buffer,FSR0L
movff &Buffer+1,FSR0H
loop:
movf POSTINC0,w // load w with next databyte
xorwf crc,f // xor with accumulated crc (accumulated crc is no longer valid now)
movlw 0 // w will accumulate the new crc
btfsc crc,0
xorlw 0x5e // could also be iorlw
btfsc crc,1
xorlw 0xbc
btfsc crc,2
xorlw 0x61
btfsc crc,3
xorlw 0xc2
btfsc crc,4
xorlw 0x9d
btfsc crc,5
xorlw 0x23
btfsc crc,6
xorlw 0x46
btfsc crc,7
xorlw 0x8c
movwf crc // store accumulated crc
decfsz byte_cntr,f
goto loop // next databyte
// done, crc is in w
movwf crc // store in result
#ENDASM
return crc;
} |
|
|
|
jonowoodhouse
Joined: 12 Feb 2007 Posts: 2 Location: Cape Town
|
crc8 - assembler c crc routine |
Posted: Mon Feb 12, 2007 11:54 am |
|
|
Hi
Firstly, to Dirk & the others - thanks very much for this code. It's been really useful.
Below please find a variation that will run for both the PIC16 (PCM) and PIC18 (PCH) PIC chips, and allows you to pass in the initial CRC value. (Make this zero if you don't want to build on a previously calculated value).
[Also, you may not need the first section (which sets up some #defines and #locates) if you have already done this, or are including in some inc file.]
Code: |
//-----------------------------------------------------------------------------
// Calculate crc8 checksum
// This is the checksum as used in the Dallas One Wire protocol.
// Advantage of this checksum over other crc's is that because of a pecularity
// of this specific polynomial it allows bytewise processing without bit
// shifting. It's very fast, small and uses no RAM.
//
// Based on: Maxim Application Note 27,
// http://www.maxim-ic.com/appnotes.cfm/appnote_number/542
// Original C code: T. Scott Dattalo
// http://www.dattalo.com/technical/software/pic/crc_8bit.c
// Optimized by: Dirk Van den Berge (dvdb)
// donated to the CCS-forum 12-jan-2004
// http://www.ccsinfo.com/forum/viewtopic.php?t=17170
// Minor tweaks by: Jono Woodhouse (jonowoodhouse) and ckielstra
// http://www.ccsinfo.com/forum/viewtopic.php?t=17170
// http://www.ccsinfo.com/forum/viewtopic.php?t=26264
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Setup FSR and INDF
#if defined(__PCM__) // For example (and tested on) PIC16F74, PIC16F887
#locate FSR = 0x0004
#locate INDF = 0x0000
#elif defined(__PCH__) // For example (and tested on) PIC18F4520
#define FSR0 0x0000
#define INDF0 0x0FEF
#define POSTINC0 0x0FEE
#locate FSR0L = 0x0FE9
#locate FSR0H = 0x0FEA
#locate STATUS = 0x0FD8
#else
#Error You need to setup the above for your PIC Chip
#endif
//-----------------------------------------------------------------------------
// This is the crc8 function for use on the PIC16 and PIC18 etc. microprocessors
unsigned int8 crc8_pic(unsigned int8* p_data, unsigned int8 p_datalength, unsigned int8 crc) {
#ASM
#if defined(__PCM__)
movf p_data, W // copy pointer to w reg..
movwf FSR // ..to pointer register
#elif defined(__PCH__)
movff p_data, FSR0L // copy low byte of pointer to low byte of pointer register 0..
movff &p_data+1, FSR0H // copy high byte of pointer to high byte of pointer register 0..
#else
#Error You need to setup the above for your PIC Chip
#endif
loop:
#if defined(__PCM__)
movf INDF, W // load w with next databyte
incf FSR // do a 8-bit increment - increment indirection register to point to next databyte - for the next time
#elif defined(__PCH__)
movf POSTINC0, W // load w with next databyte and increment indirection register to point to next databyte - for the next time
#else
#Error You need to setup the above for your PIC Chip
#endif
xorwf crc, F // xor with accumulated crc (accumulated crc is no longer valid now)
movlw 0 // w will accumulate the new crc
btfsc crc, 0
xorlw 0x5e // could also be iorlw
btfsc crc, 1
xorlw 0xbc
btfsc crc, 2
xorlw 0x61
btfsc crc, 3
xorlw 0xc2
btfsc crc, 4
xorlw 0x9d
btfsc crc, 5
xorlw 0x23
btfsc crc, 6
xorlw 0x46
btfsc crc, 7
xorlw 0x8c
movwf crc // store accumulated crc
decfsz p_datalength, F
goto loop // next databyte
movwf crc // done, crc is in w - now store it in result (crc)
#ENDASM
return(crc);
}
//-----------------------------------------------------------------------------
|
I've tested this on a PIC16F74, PIC16F884, PIC16F887 & PIC18F4520.
Cheers
Jono Woodhouse |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jun 15, 2011 7:15 am |
|
|
I like Jono's version because it is more flexible than the original posting. I made a few minor tweaks to make better use of the newer compiler options (tested in v3.249 and 4.077):
- For the PIC18 the LFSR instruction is supported from v3.249 and up. This saves 4 bytes.
- Added the GETENV directive to get the addresses for the Special Function Registers instead of using hard coded values.
- Renamed p_datalength to datalength as it is not a pointer.
Code: | //-----------------------------------------------------------------------------
// Calculate crc8 checksum
// This is the checksum as used in the Dallas One Wire protocol.
// Advantage of this checksum over other crc's is that because of a pecularity
// of this specific polynomial it allows bytewise processing without bit
// shifting. It's very fast, small and uses no RAM.
//
// Based on: Maxim Application Note 27,
// http://www.maxim-ic.com/appnotes.cfm/appnote_number/542
// Original C code: T. Scott Dattalo
// http://www.dattalo.com/technical/software/pic/crc_8bit.c
// Optimized by: Dirk Van den Berge (dvdb)
// donated to the CCS-forum 12-jan-2004
// http://www.ccsinfo.com/forum/viewtopic.php?t=17170
// Minor tweaks by: Jono Woodhouse (jonowoodhouse) and ckielstra
// http://www.ccsinfo.com/forum/viewtopic.php?t=26264
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Setup Index Register locations (FSR and INDF)
#if defined(__PCM__) // For example (and tested on) PIC16F74, PIC16F887
#byte FSR = GETENV("SFR:FSR")
#byte INDF = GETENV("SFR:INDF")
#elif defined(__PCH__) // For example (and tested on) PIC18F4520
#byte POSTINC0 = GETENV("SFR:POSTINC0")
#else
#Error You need to setup the above for your PIC Chip
#endif
//-----------------------------------------------------------------------------
// This is the crc8 function for use on the PIC16 and PIC18 etc. microprocessors
unsigned int8 Calc_Crc8(unsigned int8* p_data, unsigned int8 datalength, unsigned int8 crc)
{
#ASM
#if defined(__PCM__)
movf p_data, W // copy pointer to w reg..
movwf FSR // ..to indirection register
#elif defined(__PCH__)
lfsr 0, p_data // copy pointer to indirection register 0
#else
#Error You need to setup the above for your PIC Chip
#endif
loop:
#if defined(__PCM__)
movf INDF, W // load W with next databyte
incf FSR // do a 8-bit increment - increment indirection register to point to next databyte - for the next time
#elif defined(__PCH__)
movf POSTINC0, W // load w with next databyte and increment indirection register to point to next databyte - for the next time
#else
#Error You need to setup the above for your PIC Chip
#endif
xorwf crc, F // xor with accumulated crc (accumulated crc is no longer valid now)
movlw 0 // W will accumulate the new crc
btfsc crc, 0
xorlw 0x5e // could also be iorlw
btfsc crc, 1
xorlw 0xbc
btfsc crc, 2
xorlw 0x61
btfsc crc, 3
xorlw 0xc2
btfsc crc, 4
xorlw 0x9d
btfsc crc, 5
xorlw 0x23
btfsc crc, 6
xorlw 0x46
btfsc crc, 7
xorlw 0x8c
movwf crc // store accumulated crc
decfsz datalength, F
goto loop // next databyte
movwf crc // done, crc is in W - now store it in result (crc)
#ENDASM
return crc;
} |
|
|
|
pozzari
Joined: 30 Oct 2010 Posts: 3
|
Don't work with pic12f675 |
Posted: Sat Apr 14, 2012 12:05 am |
|
|
Don't work with pic12f675.
But works fine with other MCU´s.
Thanks |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Mon Sep 01, 2014 2:24 pm |
|
|
Hi,
Can you post a small sample program on how to use this?
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Sep 09, 2014 4:22 pm |
|
|
Turns out that for PCH there are still problems with the LFSR assembly instruction. It is not loading the pointer but the address of the registers holding the pointer.
Here is a fixed version where the FSR register is loaded using plain C code. Easier to read and portable for both PCM and PCH.
Also added example code.
Code: | #include <18F458.h>
#FUSES HS, NOWDT, PUT, NOLVP
#device PASS_STRINGS=IN_RAM
#use delay(clock=4MHz)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <stdlib.h> // for strlen()
//-----------------------------------------------------------------------------
// Calculate crc8 checksum
// This is the checksum as used in the Dallas One Wire protocol.
// Advantage of this checksum over other crc's is that because of a pecularity
// of this specific polynomial it allows bytewise processing without bit
// shifting. It's very fast, small and uses no RAM.
//
// Code downloaded from: http://www.ccsinfo.com/forum/viewtopic.php?t=26264
//
// Based on: Maxim Application Note 27,
// http://www.maximintegrated.com/en/app-notes/index.mvp/id/27
// Original C code: T. Scott Dattalo
// http://www.dattalo.com/technical/software/pic/crc_8bit.c
// 2004-01-12: Dirk Van den Berge (dvdb)
// - Optimizations and CCS conversion.
// http://www.ccsinfo.com/forum/viewtopic.php?t=17170
// 2007-02-12: Jono Woodhouse (jonowoodhouse)
// - Will now run for both the PIC16 (PCM) and PIC18 (PCH) PIC chips.
// - Allow to pass in the initial CRC value. (Make this zero if you don't want
// to build on a previously calculated value).
// 2011-06-15: C. Kielstra
// - Save 4 bytes for PCH by using the LFSR instruction.
// - Made more flexible by using the GETENV directive to get the addresses for
// the Special Function Registers instead of using hard coded values.
// - Renamed p_datalength to datalength as it is not a pointer.
// 2014-09-09: C. Kielstra
// - Fix: On PIC18 loading the FSR register through the LFSR assembly command
// didn't work. Now replaced by a line of C code that is easier to read and
// works both on PIC16 and PIC18.
// - Added example program.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Setup Index Register locations (FSR and INDF)
#if defined(__PCM__) // For example (and tested on) PIC16F74, PIC16F887
#byte FSR = GETENV("SFR:FSR")
#byte INDF = GETENV("SFR:INDF")
#elif defined(__PCH__) // For example (and tested on) PIC18F458
#word FSR = GETENV("SFR:FSR0L")
#byte POSTINC0 = GETENV("SFR:POSTINC0")
#else
#Error You need to setup the above for your PIC chip
#endif
//-----------------------------------------------------------------------------
// This is the crc8 function for use on the PIC16 and PIC18 etc. microprocessors
unsigned int8 Calc_Crc8(unsigned int8 *p_data, unsigned int8 datalength, unsigned int8 crc)
{
FSR = p_data; // Load the indirection register
#ASM
loop:
#if defined(__PCM__)
movf INDF, W // load W with next databyte
incf FSR // do a 8-bit increment - increment indirection register to point to next databyte - for the next time
#elif defined(__PCH__)
movf POSTINC0, W // load w with next databyte and increment indirection register to point to next databyte - for the next time
#else
#Error You need to setup the above for your PIC Chip
#endif
xorwf crc, F // xor with accumulated crc (accumulated crc is no longer valid now)
movlw 0 // W will accumulate the new crc
btfsc crc, 0
xorlw 0x5e // could also be iorlw
btfsc crc, 1
xorlw 0xbc
btfsc crc, 2
xorlw 0x61
btfsc crc, 3
xorlw 0xc2
btfsc crc, 4
xorlw 0x9d
btfsc crc, 5
xorlw 0x23
btfsc crc, 6
xorlw 0x46
btfsc crc, 7
xorlw 0x8c
movwf crc // store accumulated crc
decfsz datalength, F
goto loop // next databyte
movwf crc // done, crc is in W - now store it in result (crc)
#ENDASM
return crc;
}
void main()
{
int8 crc;
int8 length;
char message[] = "Hello world.";
// Example when you have to calculate the CRC over a message in one go.
length = strlen(message);
crc = Calc_Crc8(message, length, 0);
printf("CRC-1 = %u\n", crc);
// Example when you have to calculate the CRC in multiple steps.
crc = 0; // Set the CRC start value. 1-wire protocol uses 0, other protocols often start with 0xFF.
crc = Calc_Crc8("Hello", 5, crc);
crc = Calc_Crc8(" ", 1, crc);
crc = Calc_Crc8("world.", 6, crc);
printf("CRC-2 = %u\n", crc);
}
// Generated output:
// CRC-1 = 105
// CRC-2 = 105 |
|
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Sep 10, 2014 7:59 am |
|
|
Thanks for the sample program!
Kind regards,
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|