This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F280025: Incorrect output using the CRC routine provided on page 642 of SPRUHS1C

Part Number: TMS320F280025
Other Parts Discussed in Thread: CONTROLSUITE, C2000WARE

Hi Team,

Here's an issue from the customer may need your help:

The .asm file that the customer created is shown below:

called assembly function:

Uint16 inputdata[6]= {1,2,3,4,5,6};

mycrc.CRCData = inputdata;
mycrc.CRCLen = 12;

CRC16P1(&mycrc);

The returned result is 0x8059, which does not correspond to the correct result 0xDDBA.

What is the reason?

--

Thanks & Regards

Yale

  • Hi Yale,

    Let me check the function with our SW team. Can confirm the polynomial used to calculate expected correct result ?

    Regards,

    Vivek Singh 

  • Thanks Vivek,

    Here it is: 

    CRC-16-MODBUS
        x16+x15+x2+1

    The correct result calculated by online calculation is 0xDDBA.

    --

    Thanks & Regards

    Yale

  • Hi Yale,

    Thanks. In this you have initial value as FFFF. Can you try making it 0000 and see if that helps.

    Regards,

    Vivek Singh

  • Hi Vivek,

    Feedback from the customer:

    The initial value of this check mode is fixed 0xFFFF.

    I tried the routines in controlSUITE\libs\dsp\VCU\v110\source\C28x_VCU_LIB and the result is also wrong. The .asm file code is as follows:

    ; -------------------
    ; Calculate the CRC of a block of data
    ; This function assumes the block is a multiple of 2 16-bit words
    ;
    		.if __TI_EABI__
    	  	.asg getCRC16P1_vcu, _getCRC16P1_vcu
    	  	.asg CRC16P1 , _CRC16P1
    	  	.asg getCRC16P2_vcu, _getCRC16P2_vcu
    	  	.endif
    
    ;	  	.def _getCRC16P1_vcu
    ;		.def    CRC16P1
    		.global _CRC16P1
    		.global _getCRC16P2_vcu
    		.global	_getCRC16P1_vcu
    
    ;		.text
    
    _CRC16P1
    		VCRCCLR 					; Clear the result register
    		MOV		AL, 	*+XAR4[4] 	; AL = CRCLen
    		ASR 	AL, 	2 			; AL = CRCLen/4
    		SUBB 	AL, 	#1 			; AL = CRCLen/4 - 1
    		MOVL 	XAR7, 	*+XAR4[2]	; XAR7 = &CRCData
    		.align 2
    		NOP 						; Align RPTB to an odd address
    		RPTB _CRC16P1_done, AL 		; Execute block of code AL + 1 times
    		VCRC16P1L_1 *XAR7 			; Calculate CRC for 4 bytes
    		VCRC16P1H_1 *XAR7++ 		; ...
    		VCRC16P1L_1 *XAR7 			; ...
    		VCRC16P1H_1 *XAR7++ 		; ...
    
    _CRC16P1_done
    		MOVL 	XAR7, 	*+XAR4[0] 	; XAR7 = &CRCResult
    		VMOV32 	*+XAR7[0], VCRC 	; Store the result
    		LRETR						; return to caller
    
    
    
    
    
    _getCRC16P2_vcu:
    	  PUSH		  XAR0
    	  PUSH        XAR1
    
    	  MOVZ        AR0, *-SP[7]        ; load rxLen
          ADDB        SP, #4              ; allocate 4 words for local
          VMOV32      *-SP[2], VCRC       ; Store current CRC
          VCRCCLR
          MOVL        *-SP[4], ACC
          VMOV32      VCRC,*-SP[4]        ; VCRC = Inital value
          MOV         AL,AR5              ; check the parity
          SBF         _CRC16p2_loop_prep, EQ
          VCRC16P2H_1 *XAR4++             ; if parity=1, calculate high byte first
          DEC         AR0
          SBF         _CRC16p2done, EQ
    _CRC16p2_loop_prep:
          MOV         AL, AR0
          MOV         AH, AR0
          AND         AL, #0xFFF8         ; check to see if the length is greater than 8 bytes
          BF          _CRC16p2_LSB,EQ
          LSR         AL, #3              ; loop in 8 bytes
          MOV         AR1, AL
          SUB         AR1, #1
    
          .align     (2)                  ; align at 32-bit boundary to remove penalty
          RPTB        _CRC16p2_post, AR1  ; loop for the middle part of the packet
          VCRC16P2L_1 *XAR4
          VCRC16P2H_1 *XAR4++
          VCRC16P2L_1 *XAR4
          VCRC16P2H_1 *XAR4++
          VCRC16P2L_1 *XAR4
          VCRC16P2H_1 *XAR4++
          VCRC16P2L_1 *XAR4
          VCRC16P2H_1 *XAR4++
    _CRC16p2_post
          LSL         AL, #3              ; calculating remaining number of bytes
          SUB         AH, AL
          SBF         _CRC16p2done, EQ	  ;branch to end on 0 remainder
          MOV         AR0, AH
    _CRC16p2_LSB
          VCRC16P2L_1 *XAR4               ; if parity=0, calculate the low byte
          DEC         AR0
          SBF         _CRC16p2done, EQ
          VCRC16P2H_1 *XAR4++
          DEC         AR0
          SBF         _CRC16p2_LSB, NEQ
    _CRC16p2done
          VMOV32       *-SP[4], VCRC        ; Store CRC
          MOV          AL, *-SP[4]          ; return AL
          VMOV32       VCRC, *-SP[2]        ; Restore VCRC
          SUBB         SP, #4               ; restore stack pointer
          POP          XAR1
          POP		   XAR0
          LRETR
    
    
    _getCRC16P1_vcu:
    	  PUSH 		  XAR0
    	  PUSH        XAR1
    
    	  MOVZ        AR0, *-SP[7]        ; load rxLen
          ADDB        SP, #4              ; allocate 4 words for local
          VMOV32      *-SP[2], VCRC       ; Store current CRC
          VCRCCLR
          MOVL        *-SP[4], ACC
          VMOV32      VCRC,*-SP[4]        ; VCRC = Inital value
          MOV         AL, AR5             ; check the parity
          SBF         _CRC16p1_loop_prep, EQ
          VCRC16P1H_1 *XAR4++             ; if parity=1, calculate high byte first
          DEC         AR0
          SBF         _CRC16p1done, EQ
    _CRC16p1_loop_prep:
          MOV         AL, AR0
          MOV         AH, AR0
          AND         AL, #0xFFF8         ; check to see if the length is greater than 8 bytes
          BF          _CRC16p1_LSB,EQ
          LSR         AL, #3              ; loop in 8 bytes
          MOV         AR1, AL
          SUB         AR1, #1
    
          .align     (2)                  ; align at 32-bit boundary to remove penalty
          RPTB        _CRC16p1_post, AR1  ; loop for the middle part of the packet
          VCRC16P1L_1 *XAR4
          VCRC16P1H_1 *XAR4++
          VCRC16P1L_1 *XAR4
          VCRC16P1H_1 *XAR4++
          VCRC16P1L_1 *XAR4
          VCRC16P1H_1 *XAR4++
          VCRC16P1L_1 *XAR4
          VCRC16P1H_1 *XAR4++
    _CRC16p1_post
          LSL         AL, #3              ; calculating remaining number of bytes
          SUB         AH, AL
          SBF         _CRC16p1done, EQ	  ;branch to end on 0 remainder
    	  MOV         AR0, AH
    _CRC16p1_LSB
          VCRC16P1L_1 *XAR4               ; if parity=0, calculate the low byte
          DEC         AR0
          SBF         _CRC16p1done, EQ
          VCRC16P1H_1 *XAR4++
          DEC         AR0
          SBF         _CRC16p1_LSB, NEQ
    _CRC16p1done
          VMOV32       *-SP[4], VCRC        ; Store CRC
          MOV          AL, *-SP[4]          ; return AL
          VMOV32       VCRC, *-SP[2]        ; Restore VCRC
          SUBB         SP, #4               ; restore stack pointer
          POP          XAR1
          POP		   XAR0
          LRETR

    The function call code is as follows:

    typedef enum{
        CRC_parity_even = 0,
        CRC_parity_odd = 1
    }CRC_parity_e;
    
    typedef struct {
        Uint32 *CRCResult;      // Address where result should be stored
        Uint16 *CRCData;        // Start of data
        Uint16 CRCLen ;          // Length of data in bytes
    }CRC_CALC;
    CRC_CALC mycrc;
    
    extern Uint32 CRC16P1(CRC_CALC *mycrc);
    extern Uint16 getCRC16P1_vcu(Uint32 input_crc16_accum, Uint16 *msg, CRC_parity_e parity, Uint16 rxLen);
    extern Uint16 getCRC16P2_vcu(Uint32 input_crc16_accum, Uint16 *msg, CRC_parity_e parity, Uint16 rxLen);
    
    Uint32 CRC16resultP1;
    Uint32 CRC16resultP2;
    Uint16 inputdata[6]= {0x01,0x02,0x03,0x04,0x05,0x06};
    static const Uint16 CRC16inputdata[6] = {0x01,0x02,0x03,0x04,0x05,0x06};
    void main(void)
    {
        //mycrc.CRCResult = TESTresult;
        mycrc.CRCData = inputdata;
        mycrc.CRCLen = 6;
    
        while(1)
        {
            CRC16P1(&mycrc);
            CRC16resultP1 = getCRC16P1_vcu(0xFFFF, (Uint16*)CRC16inputdata, (CRC_parity_e)CRC_parity_even, 6);
            CRC16resultP2 = getCRC16P2_vcu(0xFFFF, (Uint16*)CRC16inputdata, (CRC_parity_e)CRC_parity_even, 6);
        }

    And the result is

    *(CRCResult) = 0x00001800;

    CRC16resultP1 = 0x00005AD8,CRC16resultP2  = 0x0000F38B,

    If change the initial value to 0x0000, the result is

    CRC16resultP1 = 0x00005A00,CRC16resultP2  = 0x0000FD9B,

    The above results do not correspond to the online calculation results, and the correct result should be 0xDDBA.

    https://www.lddgo.net/en/encrypt/crc

    When I use VCU to verify, the verification method is CRC-16-MODBUS   x16+x15+x2+1.

    Is the routine I'm using wrong? Which routine should I use?

    --

    Thanks & Regards

    Yale

  • Yale,

    Uint16 inputdata[6]= {0x01,0x02,0x03,0x04,0x05,0x06};

    This is going to end up being 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006

    Then when you compute the CRC on 6 bytes, it will get computed in the following order LSB-MSB-LSB-MSB, therefore you are computing the CRC on 0x01-0x00-0x02-0x00-0x03-0x00.

    If you want to compute it on 0x01-0x02-0x03-0x04-0x05-0x06, in that order, your input buffer needs to be defined as

    Uint16 inputdata[3] ={0x0201, 0x0403, 0x0605};

    Thanks,

    Sira

  • Hi Sira,

    Thanks for your reply.

    Based on the method that you provided, my customer changed 

    Uint16 inputdata[6]= {0x01,0x02,0x03,0x04,0x05,0x06};
    
    Uint16 CRC16inputdata[3] ={0x01,0x02,0x03,0x04,0x05,0x06};

    to

    Uint16 inputdata[3]= {0x0201,0x0403,0x0605};
    
    Uint16 CRC16inputdata[3] ={0x0201,0x0403,0x0605};

    and the result is

    *(CRCResult) = 0x00009E33;

    CRC16resultP1 = 0x0000DA6F,

    CRC16resultP2  = 0x0000D71C.

    where CRC16resultP2  = 0x0000D71C fits the result of the polynomial CRC-16-CCITT-FALSE   x16+x12+x5+1.

    But the customer needs polynomial CRC-16-MODBUS   x16+x15+x2+1's VCU calculation routines.

    How does my customer need to modify to get the desired result?

    --

    Thanks & Regards

    Yale

  • Yale,

    In the picture you shared of the online CRC calculator tool, what do the check marks on REFIN and REFOUT in the Reverse field refer to?

    Thanks,

    Sira

  • Hi Sira,

    When REFIN is True, each byte of the input raw data needs to be processed in reverse order. Attention please: For each byte, not the entire data, take a 4-byte raw data as an example:

    When REFOUT is True, the output data needs to be processed in reverse order of the entire data. Attention please: The reverse order operation done here is different from REFIN, it is not byte reverse order, but the entire reverse order. Taking CRC-32 as an example, the final data is 32 bits. When REFOUT is True, the reverse is as follows:

    --

    Thanks & Regards

    Yale

  • Yale,

    So are you using the corresponding settings when calculating the CRC i.e. bit reversing the input bytes through the VSETCRCMSGFLIP instruction, and bit reversing the output (e.g. through the __flip32() intrinsic).

    C2000Ware has an example that could help, it has both a regular compute as well as a bit reversed compute (called Reflected).

    C:\ti\c2000\C2000Ware_5_00_00_00\libraries\dsp\VCU\c28\examples\crc\28003x_vcrc_crc_16

    Thanks,

    Sira