Introduction.
When data is communicated between two devices, it is common to use some type of error checking. Common examples are parity, a checksum and a cyclic redundancy check (CRC). The general idea is that the transmitter calculates and transmits a value and the receiver performs the same calculations and compares the result with the check value.
When interfacing with the Dallas 1820 1-wire digital thermometer, various commands are issued by the PIC to a specific DS1820 and data is then returned to the PIC as a series of nine bytes. Eight of these bytes contain data related to the temperature or are user bytes. The ninth and final byte is the cyclic redundancy check (CRC).
The DS1820 calculates this final CRC byte using a defined algorithm to operate on the other eight data bytes.
The receiving processor may then operate on the eight received data bytes using the same algorithm and compare this calculated CRC with that calculated by the DS1820. If the two do not agree, a transmission error has occurred and the designer may opt to structure the program so as to repeat the process until the two CRCs do agree.
Detailed Discussion.
The algorithm is based on the 8-bit shift register model as shown. Note that the shift register is initially cleared.
For each data bit received, the bit is exclusive ored with the least significant bit of the shift register. The result is termed the feedback bit. The feedback bit is then exclusive ored with bits 4 and 3 in the shift register, the shift register is shifted one place to the right and the feedback bit is inserted in the most significant bit position.
Thus, if the shift register was originally;
D7 D6 D5 D4 D3 D2 D1 D0The new value is
FB D7 D6 D5 D4^FB D3^FB D2 D1Where;
FB = D0 ^ data_bitAnother way of looking at this, is to calculate the feedback bit by exclusive oring the data bit with the least significant bit of the shift register. Then shift the shift register one place to the right. Thus, the most significant bit is now zero, former bits 4 and bits 3 are now in the bit 3 and bit 2 positions and then exclusive or bits 7, 3 and 2 with the feedback bit.
However, consider the truth table for the an exclusive or function.
LINE X Y Q (1) 0 0 0 (2) 0 1 1 (3) 1 0 1 (4) 1 1 0Note that in lines (1) and (3), that any quantity exclusive ored with a 0 is the quantity itself.
This, if the feedback bit is zero, there is no need to exclusive or bits 7, 3 and 2 with a zero. Bit 7 is already a logic zero, the value of the feedback bit. Exclusive oring bits 3 and 2 with a zero will produce the same values of bits 3 and 2.
Note that in lines (2) and (4), that any quantity exclusive ored with a logic one is the inverse of the original quantity. Thus, if the feed back bit is a logic one, one need only invert bits 7, 3 and 2. That is, after the shift, bit 7 is a logic zero. However, by exclusive oring it with a logic one, it becomes a one which is the value of the feedback bit. By exclusive oring bits 3 and 2 with a logic one, they are inverted.
Thus, a simple algorithm using the C language;
byte calc_CRC_bit (byte shift_reg, byte data_bit) { byte fb; fb = (shift_reg & 0x01) ^ data_bit; /* exclusive or least sig bit of current shift reg with the data bit */ shift_reg = shift_reg >> 1; / * shift one place to the right */ if (fb==1) { shift_reg = shift ^ 8C; /* CRC ^ binary 1000 1100 */ } return(shift_reg); }The above routine is called for each byte received. Thus, in the case of the DS1820, eight bytes (64 data bits) are received and the above algorithm is applied 64 times. The result is the CRC value.
An interesting property of this algorithm is that if the shift register has a particular value and if the same byte value is then applied, the result will be zero.
For example, if after receiving 64 bits from the DS1820, assume the receiving processor has calculated the value of the shift register as 0x3C. The DS1820 will then send the calculated 8-bit CRC which will be 0x3C if no transmission errors have occurred. When the receiving processor applies the above algorithm to the additional eight bits, the result will be zero.
Thus, by applying this algorithm to the eight data bytes and then finally to the CRC byte, a result of zero indicates no transmission errors.
In the following program, the nine values received from the DS1820 are displayed on lines 1, 2 and 3 of the PIC-n-LCD display. The result of the CRC algorithm is displayed on line 4. Note that it should be zero.
In the CRC calculation, variable SHIFT_REG is initially cleared.
As each value is received from the DS1820, the byte is passed to CALC_CRC_BYTE which isolates each of the eight bits, beginning with the least significant and passes the value to CALC_CRC_BIT in variable DATA_BIT.
; Program 1820_CRC.ASM ; ; Performs temperature measurement. No addressing. ; ; Illustrates the calculation of the cyclic redundancy check (CRC). ; ; Program fetches the nine bytes from the DS1820. These are displayed ; on the PIC-n-LCD using the LCD module which is included near the end ; of this program. ; ; The CRC result is calculated and displayed. ; ; Although values are saved in a data buffer for later use, they are ; not used in this program. ; ; 16C84 DS1820 ; PortB.0 (term 6) ------------------------------ DQ (term 2) ; ; PORTA, Bit 0 (terminal 17) ------ TX ----------> to RX on Serial LCD ; ; ; copyright, Peter H. Anderson, June, '98 LIST p=16f84 #include <c:\mplab\p16f84.inc> __CONFIG 11h CONSTANT DATA_PIN=0 CONSTANT BASE_VAR=0C CONSTANT DATA_BUFF=28H CONSTANT BUFF_SIZE=7 N EQU BASE_VAR+0 INDEX EQU BASE_VAR+1 ; these vars used by the O_BYTE EQU BASE_VAR+2 ; common 1-wire routines I_BYTE EQU BASE_VAR+3 TEMP EQU BASE_VAR+4 LOOP1 EQU BASE_VAR+5 ; used for timing TEMP_1 EQU BASE_VAR+6 ; used for calculating CRC DATA_BIT EQU BASE_VAR+7 SHIFT_REG EQU BASE_VAR+8 FB EQU BASE_VAR+9 TEMP_MSB EQU DATA_BUFF+0 ; first location in DATA_BUFF TEMP_LSB EQU DATA_BUFF+1 TH_UB1 EQU DATA_BUFF+2 TL_UB2 EQU DATA_BUFF+3 COUNT_REM EQU DATA_BUFF+4 COUNT_D_C EQU DATA_BUFF+5 CRC EQU DATA_BUFF+6 ORG 000H MAIN: BSF STATUS, RP0 BCF TRISA, 0 BCF STATUS, RP0 BCF PORTA, 0 ; set serial output to idle MOVLW 0CH ; clear the LCD CALL LCD_CHAR CALL INIT ; init DS1820 MOVLW 0CCH ; skip ROM MOVWF O_BYTE CALL OUT_BYTE MOVLW 44H ; perform temperature conversion MOVWF O_BYTE CALL OUT_BYTE CALL WAIT ; wait for conversion to complete ; wait for all ones from 1820 CALL INIT MOVLW 0CCH ; skip ROM MOVWF O_BYTE CALL OUT_BYTE MOVLW 0BEH ; read scratchpad MOVWF O_BYTE CALL OUT_BYTE CLRF SHIFT_REG ; initialize the CRC calculation MOVLW 0CH ; clear the LCD CALL IN_BYTE ; get from DS1820 and save MOVWF TEMP_MSB CALL LCD_VAL ; display the value CALL CALC_CRC_BYTE MOVLW " " ; space CALL LCD_CHAR CALL IN_BYTE MOVWF TEMP_LSB CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW " " ; space CALL LCD_CHAR CALL IN_BYTE MOVWF TH_UB1 CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW " " ; space CALL LCD_CHAR CALL IN_BYTE MOVWF TL_UB2 CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW 0DH ; new line on LCD CALL LCD_CHAR MOVLW 0AH CALL LCD_CHAR CALL IN_BYTE ; these two values are not saved in buffer CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW " " CALL LCD_CHAR CALL IN_BYTE CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW " " CALL LCD_CHAR CALL IN_BYTE MOVWF COUNT_REM CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW " " CALL LCD_CHAR CALL IN_BYTE MOVWF COUNT_D_C CALL LCD_VAL CALL CALC_CRC_BYTE MOVLW 0DH ; new line on LCD CALL LCD_CHAR MOVLW 0AH CALL LCD_CHAR CALL IN_BYTE ; this is CRC from DS1820 MOVWF CRC CALL LCD_VAL CALL CALC_CRC_BYTE ; result now should be zero MOVLW 0DH ; new line on LCD CALL LCD_CHAR MOVLW 0AH CALL LCD_CHAR MOVF SHIFT_REG, W ; display the shift register CALL LCD_VAL ; should be zero MOVLW .120 ; 30 second delay (120 * 250 msecs) MOVWF LOOP1 MAIN_1: MOVLW .250 CALL LCD_DELAY DECFSZ LOOP1, F GOTO MAIN_1 GOTO MAIN ; do it again ;;;;;;;;;;;; CALC_CRC_BYTE: ; applies bit by bit to shift reigister algorithm MOVLW .8 MOVWF N MOVF IBYTE, W MOVWF TEMP_1 ; copy IBYTE to TEMP CALC_CRC_BYTE_1: MOVF TEMP_1, W ANDLW 01H ; isolate least significant bit MOVWF DATA_BIT CALL CALC_CRC_BIT RRF TEMP_1, F ; next data bit now in least sig bit DECFSZ N, F ; do this for each of the eight bits GOTO CALC_CRC_BYTE_1 RETURN CALC_CRC_BIT: MOVF DATA_BIT, W ; calculate the feed back bit XORWF SHIFT_REG, W ANDLW 01H MOVWF FB BCF STATUS, C ; shift_reg = shift_reg >> 1 RRF SHIFT_REG, F BTFSS FB, 0 GOTO CALC_CRC_BIT_DONE ; if FB was zero, we are done MOVLW 8CH ; otherwise, invert bits 7, 3 and 2 XORWF SHIFT_REG, F CALC_CRC_BIT_DONE: RETURN ; The following are standard 1-Wire routines. INIT: CALL PIN_HI CALL PIN_LO MOVLW .50 ; 500 us delay CALL DELAY_10USEC CALL PIN_HI MOVLW .50 ; 500 usec delay CALL DELAY_10USEC RETURN WAIT: CALL IN_BYTE MOVLW 0FFH SUBWF I_BYTE, W BTFSS STATUS, Z GOTO WAIT RETURN IN_BYTE: ; returns byte in W MOVLW .8 MOVWF INDEX CLRF I_BYTE IN_BYTE_1: CALL PIN_LO ; momentary low on DATA_PIN NOP CALL PIN_HI NOP NOP NOP NOP NOP NOP MOVF PORTB, W ; 7 usecs later, fetch from DATA_PIN MOVWF TEMP BTFSS TEMP, DATA_PIN BCF STATUS, C ; its a zero BTFSC TEMP, DATA_PIN BSF STATUS, C ; its a one RRF I_BYTE, F MOVLW .6 ; now delay 60 usecs CALL DELAY_10USEC DECFSZ INDEX, F GOTO IN_BYTE_1 MOVFW I_BYTE ; return the result in W RETURN OUT_BYTE: MOVLW .8 MOVWF INDEX OUT_BYTE_1: RRF O_BYTE, F BTFSS STATUS, C GOTO OUT_0 GOTO OUT_1 OUT_BYTE_2: DECFSZ INDEX, F GOTO OUT_BYTE_1 RETURN OUT_0: CALL PIN_LO ; bring DATA_PIN low MOVLW .6 ; for 60 usecs CALL DELAY_10USEC CALL PIN_HI GOTO OUT_BYTE_2 OUT_1: CALL PIN_LO ; momentary low CALL PIN_HI MOVLW .6 CALL DELAY_10USEC GOTO OUT_BYTE_2 ;;;;;; PIN_HI: BSF STATUS, RP0 BSF TRISB, DATA_PIN ; high impedance BCF STATUS, RP0 RETURN PIN_LO: BCF PORTB, DATA_PIN BSF STATUS, RP0 BCF TRISB, DATA_PIN ; low impedance zero BCF STATUS, RP0 RETURN DELAY_10USEC: ; provides a delay equal to W * 10 usecs MOVWF LOOP1 DELAY_10USEC_1: NOP NOP NOP NOP NOP NOP NOP DECFSZ LOOP1, F GOTO DELAY_10USEC_1 RETURN #include <lcd_f84.asm> ; PIC-n-LCD Module Version for 16F84 END