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

Dallas CRC 16 for DS2423 1-wire counter

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
simat



Joined: 05 Feb 2008
Posts: 7

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

Dallas CRC 16 for DS2423 1-wire counter
PostPosted: Tue Feb 05, 2008 7:12 am     Reply with quote

Hi,

I've found a small bug in a 16 bit CRC routine that can be used with the Dallas DS2423 - this code was originally found at http://www.piclist.com/techref/microchip/crc16ca.htm after many attempts to find a Dallas 16 bit version at this site.

The code works most of the time, it's supposed to produce a result of 0xB001h, but for some reason it can also produce 0x7000h - this may be something to do with parity ? CRC16 (2 bytes) is accessed directly to give an accumulated result.


Code:
void docrc16(int8 newbyte)
{
   int crc_lo;
   int crc_hi;
   
   #byte STATUS = 0x03
   #byte crc_lo = 0x21        // Lower Byte of CRC16
   #byte crc_hi = 0x22        // Upper Byte of CRC16
     
   #ASM
      movf   newbyte,W        ;W = input
     
      xorwf   crc_lo,W        ;W = input XOR old crc_lo
      xorwf   crc_hi,W        ;Swap old crc_hi with W
      xorwf   crc_hi,F        ;
      xorwf   crc_hi,W        ;new crc_hi = input XOR old crc_lo
      movwf   crc_lo          ;new crc_lo = old crc_hi

      movf    crc_hi,W        ;Save crc_hi in W
      swapf   crc_hi,F        ;Trade nibbles
      xorwf   crc_hi,F        ;XOR high half byte with low
      rrf     crc_hi,F        ;Initialize Carry
      btfsc   crc_hi,0
      incf    STATUS,F        ;Compliment carry
      btfsc   crc_hi,1
      incf    STATUS,F        ;Compliment carry
      btfsc   crc_hi,2
      incf    STATUS,F        ;Compliment carry
      movwf   crc_hi          ;Restore crc_hi from W

      movlw   0x01
      btfsc   STATUS,0        ; If carry
      xorwf   crc_lo,F        ; flip bit 0 of crc_lo
      movlw   0x40
      rrf     crc_hi,F        ; shift parity into crc_hi
      btfsc   STATUS,0        ; if shift out is one
      xorwf   crc_lo,F        ; flip bit 6 of crc_lo
      rlf     crc_hi,W        ; unshift crc_hi into W
      xorwf   crc_hi,F        ; combine them
      rrf     crc_hi,F        ; shift parity back into crc_hi
      movlw   0x80
      btfsc   STATUS,0        ; if shift out is one
      xorwf   crc_lo,F        ; flip bit 7 of crc_lo
       
   #ENDASM
 
}

my less efficient C version works fine all the time..

void docrc16(int8 newbyte) {

   int16 nbyte;

   nbyte = (newbyte ^ (crc16 & 0xff)) & 0xff; // Xor and return lower byte
   crc16 >>= 8;                     // Right shift 8 for upper byte
   if ((odd_parity(nbyte)) == 1) crc16 ^= 0xC001;
   (nbyte *= 0x40) & 0xffff;
   crc16 ^= nbyte;   
   (nbyte *= 0x02) & 0xffff;
   crc16 ^= nbyte;
}


int8 odd_parity(int8 testbyte) {   // get 8 bit parity - 0xff no ,0x100 yes
   int8 n;
   int8 i;
   //printf("Odd parity called \n\r");
   n = 0;
   
   for (i = 0 ; i < 8 ; i++) {
      n += testbyte & 0x01;
      testbyte = (testbyte & 0xfe) / 2 ;
   }
   return (n & 1);
}

The input sequence is -
Start Value, Input Byte, Result of Assembly CRC16 routine
CRC16= 0000, newbyte= A5 CRC16= BBC1
CRC16= BBC1, newbyte= DF CRC16= C83A
CRC16= C83A, newbyte= 01 CRC16= 1388
CRC16= 1388, newbyte= 04 CRC16= 6513
CRC16= 6513, newbyte= BF CRC16= 7D65
CRC16= 7D65, newbyte= 2A CRC16= F43C
CRC16= F43C, newbyte= 2D CRC16= 0C34
CRC16= 0C34, newbyte= 04 CRC16= D40D
CRC16= D40D, newbyte= 00 CRC16= C515
CRC16= C515, newbyte= 00 CRC16= 0F05
CRC16= 0F05, newbyte= 00 CRC16= C3CE
CRC16= C3CE, newbyte= 00 CRC16= 5443
CRC16= 5443, newbyte= BC CRC16= 4014
CRC16= 4014, newbyte= AB CRC16= 7000
Result COUNTER= 042D2ABF CRC= 7000 - incorrect (should be 0xB001h)

Start Value, Input Byte, Result of C CRC16 routine
CRC16= 0000, newbyte= A5 CRC16= 7BC0
CRC16= 7BC0, newbyte= DF CRC16= C83A
CRC16= C83A, newbyte= 01 CRC16= D389
CRC16= D389, newbyte= 04 CRC16= 6513
CRC16= 6513, newbyte= BF CRC16= 7D65
CRC16= 7D65, newbyte= 2A CRC16= F43C
CRC16= F43C, newbyte= 2D CRC16= 0C34
CRC16= 0C34, newbyte= 04 CRC16= 140C
CRC16= 140C, newbyte= 00 CRC16= 0514
CRC16= 0514, newbyte= 00 CRC16= 0F05
CRC16= 0F05, newbyte= 00 CRC16= 03CF
CRC16= 03CF, newbyte= 00 CRC16= 5443
CRC16= 5443, newbyte= BC CRC16= 4014
CRC16= 4014, newbyte= AB CRC16= B001
COUNTER= 042D2ABF and CRC= B001 - correct

Anyone got a working CRC16 for Dallas chips or any idea where I'm going wrong?

Thanks

Simon.


Last edited by simat on Tue Feb 05, 2008 10:16 am; edited 2 times in total
ckielstra



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

View user's profile Send private message

PostPosted: Tue Feb 05, 2008 9:37 am     Reply with quote

First remark: please use the 'code' buttons when posting code, this will help to preserve the layout and makes for easier reading.

Code:
#byte crc_lo = 0x21 // Lower Byte of CRC16
#byte crc_hi = 0x22 // Upper Byte of CRC16
This is dangerous code. From the CCS manual on the #byte command:
Quote:
Warning: In both cases memory at x is not exclusive to this variable. Other
variables may be located at the same location. In fact when x is a variable, then id
and x share the same memory location.
The risk you are running here is that the compiler will assign another variable to the same memory locations as your checksum. The address you have chosen is low in memory and often used by the compiler as 'scratch' memory, i.e. temporary memory for function variables, etc. It would have been better to use the #locate command which will prevent the compiler from using these memory locations.

Looking at your code I don't understand why you want to assign the CRC code variables to a fixed memory address. Nowhere in your code you are directly accessing the data at the specified address 0x20 and 0x21. Better is to leave it to the compiler as to where to store the data. Remove these two #byte lines. It will make your code easier to read, saves a few bytes and likely will fix your bug.
simat



Joined: 05 Feb 2008
Posts: 7

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

PostPosted: Tue Feb 05, 2008 10:15 am     Reply with quote

Hi ckielstra,

Thanks for the reply, i've tried the routine with the #byte lines removed and manually setting the crc_lo and crc_hi just for a test and still get the same output.

If CRC16 = 0 and I input 0xA5 into the CRC16 routine I should get 0x7BC0 out, instead I get 0xBBC1 and it's not the TV channel :-)

I was using the #byte code to access the upper and lower bytes of the 16 bit CRC16 number, the addresses were chosen from whatever CRC16 was assigned in the compiler. #locate seems to stop the C code from accessing it so making it useless for my purpose, anyway no big problem, just need this Dallas CRC to work.

At the moment I'm working on translations the following 8051 code into ASM for the 16F628A

Code:
CRC16:
        PUSH    ACC                     ;save this in case the caller needs
it
        XRL     A,CRCL
        MOV     CRCL,CRCH               ;put the high byte of the crc in its
dest..
        MOV     CRCH,A                  ;save data xor low(crc) for later
        MOV     C,P
        JNC     CRC0
        XRL     CRCL,#001H

CRC0:
        RRC     A                       ;get the low bit in c
        JNC     CRC1
        XRL     CRCL,#040H

CRC1:
        MOV     C,ACC.7
        XRL     A,CRCH                  ;compute the results for bits P...U
        RRC     A                       ;shift them into place
        MOV     CRCH,A                  ;and save them
        JNC     CRC2
        XRL     CRCL,#080H

CRC2:
        POP     ACC                     ;and restore everything and return
        RET

        end



Thanks

Simon.
simat



Joined: 05 Feb 2008
Posts: 7

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

PostPosted: Tue Feb 05, 2008 12:50 pm     Reply with quote

opted for the slightly slower version from Dallas Appnote 27

Code:
void docrc16 (int8 newbyte)
{
   int crc_lo;
   int crc_hi;
   
   #byte STATUS = 0x03
   #locate CNTR = 0xB8
   
   #byte crc_lo = 0x21        // Lower Byte of CRC16
   #byte crc_hi = 0x22        // Upper Byte of CRC16
   
   #ASM
     
         MOVLW    0x08           ; 8 bits
         MOVWF    CNTR           
       
   crc_get_bit:
         RRF      newbyte,F      ; Bit in C
         MOVF     newbyte,W      ; Value to W
         BTFSC    STATUS,0
         GOTO     crc_in_1
         BTFSS    crc_lo,0       ; Lowest bit set ?
         GOTO     crc_cont       ; Go to count with C=0
         BSF      STATUS,0
         GOTO     crc_cont       ; Go to count with C=1
     
   crc_in_1:
         BTFSC    crc_lo,0       ; Lowest bit zero ?
         BCF      STATUS,0       ; If no, C=0 = complement
         
   crc_cont:
         BTFSS    STATUS,0
         GOTO     crc_shift      ; If C=0 only shift
         BTFSC    crc_hi,6       ; Complement 15th bit of CRC
         GOTO     crc1
         BSF      crc_hi,6       ; If clear, set
         GOTO     crc2
         
   crc1:
         BCF      crc_hi,6       ; If set, clear
         
   crc2:
         BTFSC    crc_lo,1       ; Complement 2nd bit of CRC
         GOTO     crc3
         BSF      crc_lo,1
         GOTO     crc_shift
         
   crc3:
         BCF      crc_lo,1
         
   crc_shift:
         RRF      crc_hi,F       ; 16bit rotate
         RRF      crc_lo,F
         MOVF     newbyte,W
         DECFSZ   CNTR,F
         GOTO     crc_get_bit
         
   #ENDASM
}


this works..
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion 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