CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

CRC8 (Dallas 1-wire)

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

CRC8 (Dallas 1-wire)
PostPosted: Wed Mar 08, 2006 8:11 am     Reply with quote

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

View user's profile Send private message Visit poster's website

crc8 - assembler c crc routine
PostPosted: Mon Feb 12, 2007 11:54 am     Reply with quote

Hi

Firstly, to Dirk & the others - thanks very much for this code. It's been really useful. Smile

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

View user's profile Send private message

PostPosted: Wed Jun 15, 2011 7:15 am     Reply with quote

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

View user's profile Send private message

Don't work with pic12f675
PostPosted: Sat Apr 14, 2012 12:05 am     Reply with quote

Don't work with pic12f675.

But works fine with other MCU´s.
Thanks
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Mon Sep 01, 2014 2:24 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Sep 09, 2014 4:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Sep 10, 2014 7:59 am     Reply with quote

Thanks for the sample program!

Kind regards,
G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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