CRC Calculation - Need a little help


Closed Thread
Results 1 to 9 of 9
  1. #1
    Steve43's Avatar
    Steve43 Guest

    Default CRC Calculation - Need a little help

    Hi all,

    I need to calculate a CCITT-16 reversed (0x8408) checksum in PBP but need a little assistance. I've uncovered an assembly routine that would seem to do what I need ( see http://www.dattalo.com/technical/software/pic/crc.php ) but I'm not very familiar with the integration of assembly routines into a PBP program and am hoping someone can help me out a little here.

    What I need to do is send an array of bytes to this routine and come up with a two-byte checksum as a result. An example would be to send the bytes 'AA 05 01' to the routine and have the checksum 'D5 50' returned. Problem is that I don't know how to pass the variables back and forth between the BASIC program and the assembly routine, etc.

    Sorry if this is a bit elementary... (or perhaps it isn't..?)

    Anyway, would greatly appreciate any help...

    Thanks,
    Steve

  2. #2
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Just place an _underscore before any BASIC variables you want to access in assembler,
    and an _underscore in front of the assembler label you want to call from BASIC.

    Give this a shot.
    Code:
    crc_hi  VAR BYTE bank0
    crc_lo  VAR BYTE bank0
    temp    VAR BYTE bank0
    ToCrc   VAR BYTE bank0
    CRC     VAR WORD
    X       VAR BYTE
    Space   CON " "
    
    Main:
        crc_lo = 0
        crc_hi = 0
        ToCrc = $ff
        CALL crc_8408
    
        ' Show HEX value
        HSEROUT ["Input = ",IHEX2 ToCrc,Space,"Output = ",_
        IHEX4 (crc_hi << 8 | crc_lo),13,10]
        
        ' Show ASCII values
        FOR X = 2 to 8
          ToCrc = X + "0" ' Convert X val to ASCII
          CALL crc_8408
          GOSUB Show
        NEXT X
        PAUSE 1000
        GOTO Main
        
    Show:
        HSEROUT ["Input = ",DEC ToCrc-"0",Space,"Output = ",_
        IHEX4 (crc_hi << 8 | crc_lo),13,10]
        RETURN
    
    ASM
    _crc_8408
        movf	_ToCrc,W	;Load value into W
        xorwf	_crc_lo,W	;W = CD ^ ab ==> xy
        movwf	_temp		;temp = xy
        swapf	_temp,F		;W = yx
        rrf		_temp,w
        andlw	0x78		;y<<3
        xorwf	_crc_hi,W	;W = AB ^ (y<<3)
        movwf	_crc_lo		;LO = AB ^ (y<<3)
        swapf	_temp,W		;W = xy
        xorwf	_temp,W		;W = (y^x) | (x^y) = kk
        movwf	_crc_hi		;HI = kk
        andlw	0x0f		;W = 0k
        xorwf	_crc_lo,W	;W = AB ^ (y<<3) ^ k
        btfsc	_crc_hi,0	;
        xorlw	0x80		;W = AB ^ (y<<3) ^ k ^ (k<<7)
        movwf	_crc_lo		;LO = AB ^ (y<<3) ^ k ^ (k<<7)
        swapf	_temp,W		;W = xy
        andlw	0xf0		;W = x0
        xorwf	_crc_hi,F	;W = y<<4 | x^y
        rrf		_crc_hi,W	;W = (y<<4 | x^y) >> 1
        andlw	7		    ;W = x^y >> 1
        swapf	_crc_hi,F	;W = x^y<<4 | y
        xorwf	_crc_hi,F	;HI = kx ^ k>>1 = (k<<4) ^ y ^ (k>>1)
        return
    ENDASM
    Just be aware of bank & page switching as your program grows.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  3. #3
    Steve43's Avatar
    Steve43 Guest


    Did you find this post helpful? Yes | No

    Default

    Bruce,

    Thanks so much for your help! Your example is quite clear and I am able to execute it properly on my device.

    One more question if you don't mind... the CRC calculation algorithm seems to want to be passed one byte at a time, but I need to calculate a checksum for a series of bytes (as a complete set, not individually) and I'm not sure how to accumulate the result of each one-byte cycle through the checksum routine.

    As a real-world example, I need to be able to send the three bytes $AA $05 $01 into the routine and obtain the resultant accumulated checksum for all three bytes, which should produce a result of $D5 $50 (I am using a PC-based checksum program to determine what the proper output should be), but no matter what I do I can't seem to achieve this result.

    I then need to append this checksum (with the high and low order bytes reversed) to the original three-byte command for a final result of $AA $05 $01 $50 $D5 to go out the serial port.

    Once again, the help is really appreciated...

  4. #4
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    The result is already cumulative. If you compare the results
    to the assembly version in your link, you'll see the last version
    I posted outputs the same values. crc_hi & crc_lo are only
    cleared at the start - so they are cumulative until cleared.

    If you change any value, the final result will also change since
    crc_hi & crc_low hold the cumulative values from every byte
    passed to the assembly routine.

    To change the order of the final result, simply change the order
    you send them out in. crc_hi holds the high byte. crc_lo holds the
    low byte. You can send them both out serially in any order you
    need.

    Code:
    crc_hi  VAR BYTE bank0
    crc_lo  VAR BYTE bank0
    temp    VAR BYTE bank0
    ToCrc   VAR BYTE bank0
    C_Vars  VAR BYTE[3] ' Holds byte data passed to crc_8408
    X       VAR BYTE
    
    Main:
        crc_lo = 0
        crc_hi = 0
        FOR X = 0 TO 2
          LOOKUP X,[$AA,$05,$01],ToCrc
          C_Vars[X] = ToCrc ' Stash each value for Show output
          CALL crc_8408
        NEXT X
        GOSUB Show
        PAUSE 1000
        GOTO Main
       
    Show:
        HSEROUT [IHEX2 C_Vars[0],IHEX2 C_Vars[1],_
        IHEX2 C_Vars[2],IHEX crc_lo,IHEX2 crc_hi,13,10]
        RETURN
    
    ASM
    _crc_8408
        movf	_ToCrc,W	;Load value into W
        xorwf	_crc_lo,W	;W = CD ^ ab ==> xy
        movwf	 _temp		;temp = xy
        swapf	_temp,F		;W = yx
        rrf	_temp,w
        andlw	0x78		;y<<3
        xorwf	_crc_hi,W	;W = AB ^ (y<<3)
        movwf	 _crc_lo		;LO = AB ^ (y<<3)
        swapf	_temp,W		;W = xy
        xorwf	_temp,W		;W = (y^x) | (x^y) = kk
        movwf	 _crc_hi		;HI = kk
        andlw	0x0f		;W = 0k
        xorwf	_crc_lo,W	;W = AB ^ (y<<3) ^ k
        btfsc	_crc_hi,0	;
        xorlw	0x80		;W = AB ^ (y<<3) ^ k ^ (k<<7)
        movwf	 _crc_lo		;LO = AB ^ (y<<3) ^ k ^ (k<<7)
        swapf	_temp,W		;W = xy
        andlw	0xf0		;W = x0
        xorwf	_crc_hi,F	;W = y<<4 | x^y
        rrf	_crc_hi,W	;W = (y<<4 | x^y) >> 1
        andlw	7                        ;W = x^y >> 1
        swapf	_crc_hi,F	;W = x^y<<4 | y
        xorwf	_crc_hi,F	;HI = kx ^ k>>1 = (k<<4) ^ y ^ (k>>1)
        return
    ENDASM
    This doesn't return crc_hi = $D5 & crc_lo = $50 though. I get
    crc_lo = $4F & crc_hi = $7F.

    The above returns: $AA$05$01$7F$4F with your hi & lo bytes
    swapped around.

    If you change it, and plug-in the same values shown in the assembly
    version, it returns eactly the same results as the assembly version
    shows for each value passed to crc_8408.

    Maybe there's a difference in your PC version & the PIC version?
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  5. #5
    Steve43's Avatar
    Steve43 Guest


    Did you find this post helpful? Yes | No

    Default

    The result is already cumulative. If you compare the results to the assembly version in your link, you'll see the last version I posted outputs the same values. crc_hi & crc_lo are only cleared at the start - so they are cumulative until cleared.

    Yes, that's what I thought by looking at it, but I guess I was thrown by the fact that the results weren't as expected. However, some more experimentation shows that the results aren't as expected even when calculating the CRC for a single byte, so it would indeed appear that the algorithm in the assembly routine above and the one used by the PC-based program are not identical (although they both are supposed to be CCITT-16 reversed (0x8408)).

    I have the C source code for the algorithm used in the PC program. I will try to compare this against the PIC assembly routine and see where the difference might be, although unfortunately I'm no expert in either.

    Thanks again for your assistance. This forum is an incredible resource thanks to you and all of the people who contribute.

  6. #6
    Steve43's Avatar
    Steve43 Guest


    Did you find this post helpful? Yes | No

    Default

    Well, I'm just not able to get anywhere with this. I have attached C source code for a CCITT-16 Reversed (0x8408) algorithm that gives me what I need, but unfortunately the PIC assembly routine I found doesn't provide the same output. I don't know if anyone is kind enough to take this on but I could really use the assistance. I'd be willing to buy a PIC CRC library to do this but I haven't been able to find such a thing.

    Would someone like to take a stab at implementing this in PBP? It doesn't really have to be in assembly because speed isn't much of an issue in my application.

    Thanks (much) again.

    (Note: the attached file is in .RTF format to preserve the source code formatting but has an extension of .txt so I could attach it. Best to open it with Wordpad or other .RTF-aware application.)
    Attached Files Attached Files

  7. #7
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    Here ya go..!
    Code:
    Poly    con $8408   ' CRC polynomial
    I       VAR BYTE
    pData   VAR BYTE
    X       VAR BYTE
    CRC     VAR WORD
    C_Data  VAR WORD
    VAL     VAR BYTE[3] ' Holds 3 values passed to CRC routiine
    
    VAL[0] = $AA
    VAL[1] = $05
    VAL[2] = $01
    
    Begin:
        CRC = $FFFF
        for X = 0 TO 2
          pData = VAL[X]
          gosub Calc_CRC
        next X
        CRC = ~CRC
        hserout [IHEX CRC.LowByte,IHEX CRC.HighByte,13,10]
        pause 1000
        goto Begin
        
    Calc_CRC:
        C_Data = $00FF & pData
        CRC = CRC ^ C_Data
        for I = 0 to 7
            if CRC.Bit0 = 1 then
             CRC = (CRC >> 1) ^ Poly
            else
             CRC = CRC >> 1
            endif
        next I
        return
    I'll let you figure out how to send your original data with the final result, but there's your C-to-BASIC
    conversion. Much easier than the assembly routine, but still easier in C....;o]
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  8. #8
    Steve43's Avatar
    Steve43 Guest


    Did you find this post helpful? Yes | No

    Default

    Works perfectly! Thanks Bruce, I once again find myself in your debt. Your solution is simple and elegant and is actually a better option for me than what I started out with (although I did learn something by playing with the assembly integration examples.)

    Again, this forum is a great resource and thanks to you and the others who help the rest of us over the rough spots...

  9. #9
    Join Date
    Jul 2003
    Posts
    2,405


    Did you find this post helpful? Yes | No

    Default

    You're very welcome. Glad I could help...;o]

    I learn a lot here myself. Great resource.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

Similar Threads

  1. Dallas CRC8 Routines
    By Tom Estes in forum Code Examples
    Replies: 23
    Last Post: - 8th May 2018, 18:07
  2. Calculating CRC for Modbus RTU
    By tekart in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 20th January 2010, 22:42
  3. CRC Calculations
    By timmers in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 16th June 2009, 17:10
  4. Sensirion CRC
    By Tom Estes in forum Code Examples
    Replies: 3
    Last Post: - 9th November 2007, 15:09
  5. Dallas 1-Wire CRC Calculation
    By CocaColaKid in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 15th August 2005, 09:43

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts