PDA

View Full Version : Sensirion CRC



Tom Estes
- 7th November 2007, 17:52
Three different routines to calculate the Sensirion CRC as used in their temperature/humidity sensors.



Sensirion CRC
'Choose one of the following CRC routines. The table based one is the fastest
'but requires a large table in memory. The assembly language one is slower but
'doesn't require much memory. The PBP one is the slowest.
'The assembly language one was written with the PIC18 instruction set. If used
'on earlier PICs the rotate instruction will need to be changed accordingly.

'Make sure to initialize SHTCRC before calling the routine for the first time.
'Place the data to be crc'd in SHTRxCRC and call the routine. CRC will be
'accumulated in SHTCRC unless reset externally from the routine.

'PIC18F252

SHTCRC var byte 'accumulative CRC, usually initialize to zero before
'calling CRC routine for first time - used by
'all routines
SHTRxCRC var byte 'data to be added to CRC total - used by all
'routines
SHTCRCBitNo var byte 'internal to Sht_CRC_Basic, Sht_CRC_AL
SHTTestByte var byte 'internal to Sht_CRC_AL
SHTCRCTestBit var bit 'internal to Sht_CRC_Basic, Sht_CRC_AL

Sht_CRC_Basic:
' This code confirmed operational 12/30/03
' PBP version should work with all PIC series
For shtCRCbitno = 0 to 7 'Do for all 8 bits
Shtcrctestbit = shtcrc.7 ^ shtrxcrc.7 'XOR msb
shtrxcrc = shtrxcrc << 1 'Position received byte for next test
IF shtcrctestbit = 0 Then Sht_No_XOR 'If tested bits same, skip
shtcrc = shtcrc ^ $18 'Else, invert bits 4,5
Sht_No_XOR:
ShtCRC = shtcrc << 1 'Shift the CRC byte
ShtCrc.0 = shtcrctestbit 'And set its bit 0 to the xor'd value
'after shift this would be bit 8 position
Next shtCRCbitno
Return


Sht_CRC_Table:
' This code confirmed operational 12/29/03
' For PIC18 series, table may be too long for previous PIC series
Shtrxcrc = shtrxcrc ^ shtcrc
Lookup shtrxcrc, [0,49,98,83,196,245,166,151,185,136,219,234,125,76, 31,_
46,67,114,33,16,135,182,229,212,250,203,152,169,62 ,15,92,109,134,183,_
228,213,66,115,32,17,63,14,93,108,251,202,253,168, 197,244,167,150,1,_
48,99,82,124,77,30,47,184,137,218,235,61,12,95,110 ,249,200,155,170,132,_
181,230,215,64,113,34,19,126,79,28,45,186,139,216, 233,199,246,165,148,_
3,50,97,80,187,138,217,232,127,78,29,44,2,51,96,81 ,198,247,164,149,248,_
201,154,171,60,13,94,111,65,112,35,18,133,180,231, 214,122,75,24,41,190,_
143,220,237,195,242,161,144,7,54,101,84,57,8,91,10 6,253,204,159,174,128,_
177,226,211,68,117,38,23,252,205,158,175,56,9,90,1 07,69,116,39,22,129,_
176,227,210,191,142,221,236,123,74,25,40,6,55,100, 85,194,243,160,145,_
71,118,37,20,131,178,225,208,254,207,156,173,58,11 ,88,105,4,53,102,87,_
192,241,162,147,189,140,223,238,121,72,27,42,193,2 40,163,146,5,52,103,_
86,120,73,26,43,188,141,222,239,130,179,224,209,70 ,119,36,21,59,10,89,_
104,255,206,157,172], shtcrc
Return

' ********** Subroutine Sht_CRC_AL **********
' This code confirmed operational 12/31/03
' Uses PIC18 Instruction Set
ASM
_Sht_CRC_AL ; SHTxx CRC (a reflected CRC from Dallas 1wire)
MOVLW 8
MOVWF _ShtCRCBitNo ; Do this for all 8 bits of CRCByte
CRCLOOP
MOVF _ShtCRC,0 ; Put CRC into W
XORWF _ShtRxCRC,0 ; XOR CRC with CRCData
MOVWF _ShtTestByte ; Put results in TestByte
RLCF _ShtTestByte,1 ; Shift TestByte.7 into Carry bit
BTFSS STATUS,C ; If Carry = 1, do polynomial math
GOTO CRCSHIFT ; Otherwise just shift CRC and CRCByte
MOVF _ShtCRC,0 ; Get latest copy of CRC
XORLW 0x18 ; Polynomial math
MOVWF _ShtCRC ; Keep a copy of results
CRCSHIFT
RLCF _ShtCRC,1 ; Rotate CRC into carry
RLCF _ShtRxCRC,1 ; Rotate CRCData, carry shifts in but not important
DECFSZ _ShtCRCBitNo,1 ; Keep track of #times through loop
GOTO CRCLOOP ; Go to start if not looped through the 8 bits
RETURN ; Return if all 8 bits analyzed
ENDASM

CocaColaKid
- 8th November 2007, 19:38
This is the code I use for calculating the CRC from the Dallas 18B20 temperature sensor. The only difference I can notice is the locations of the << and >> in the two code. Can you give me an example of how your code is used cause I'm still a little fuzzy on what data does where. I know the CRC value byte is the third byte but not sure what bytes are used to calculate the CRC to compare to this value.



------------------------ Calculate the CRC from Byte 9 ------------------------

GetCRC:
for x = 0 to 7
databyte = dq[x]
gosub CalcCRC
next x
if dq[8] <> crccalc then
sensorerror = 1
else
sensorerror = 0
endif
crccalc = 0
return

'--------------------- CRC Bit Calcuation Method -------------------------------

CalcCRC:
for i = 0 to 7
databit = crccalc.0 ^ databyte.0
databyte = databyte >> 1
if databit = 0 then Shift
crccalc = crccalc ^ $18

shift:
crccalc = crccalc >> 1
crccalc.7 = databit
next i
return




'------------------ Read SHT71 Temperature / Humidity Sensor -------------------

ReadSHT71:
gosub Initialize
Sensorcmd = ReadTemp
gosub readsensor
if result => 4000 then
tempC = result - 4000
SignC = 160
else
tempC = 4000 - result
SignC = "-"
endif
gosub ConvertToKelvin
gosub ConvertToFahrenheit
gosub Initialize
Sensorcmd = ReadHumidity
gosub readsensor

'--------------------- Calculate Relative Humidity -----------------------------

w = result * 405
w = div32 100
x = result * result
x = div32 1000
x = x * 28
x = div32 100
RHLinear = w - x - 400

'---------- Calculate Relative Humidity with Temperature Compensation ----------

w = (8 * result + 1000) / 10
if SignC = 160 then
if tempC > 2500 then
x = (tempC - 2500) * w
x = div32 100
RHTempComp = RHLinear + x / 100
else
x = (2500 - temp) * w
x = div32 100
RHTempComp = RHLinear - x / 100
endif
else
x = (2500 + tempC) * w
x = div32 10000
RHTempComp = RHLinear - x
endif
sleep 1
return

'---------------------------- Initialize the Sensor ----------------------------

Initialize:
high DataPin
low clk
for i = 1 to 10
high clk
pause 1
low clk
pause 1
next i
call TransferStart
return

'---------------------------- Get Data from Sensor -----------------------------

ReadSensor:
gosub TransferStart
gosub WaitSensor
shiftout DataPin,clk,1,[Sensorcmd\8] ' Send command byte
input DataPin ' Wait for acknowledge
low clk
while DataPin = 1
wend
pulsout clk,10 ' Send acknowledge
while DataPin = 0
wend
while DataPin = 1 ' Wait for conversion to complete
wend
low clk
shiftin DataPin,clk,0,[result.byte1\8] ' Get the first byte, 8 bits
low DataPin
pulsout clk,10 ' Send acknowledge
shiftin DataPin,clk,0,[result.byte0\8] ' Get the second byte, 8 bits
low DataPin
pulsout clk,10 ' Send acknowledge
shiftin DataPin,clk,0,[crc\8] ' Get third byte, 8 bits, CRC
high DataPin
pulsout clk,10 ' Send acknowledge
input DataPin ' End of Transmission
input clk
return

'---------------------------- Start Transfer -----------------------------------

TransferStart:
high clk
pause 1
low DataPin
pause 1
low clk
pause 1
high clk
pause 1
high DataPin
pause 1
low clk
return

'---------------------------- Wait for Sensor ----------------------------------

WaitSensor:
result = 4096

Loop:
result = result - 1
if DataPin && result.bit11 then Loop
return

'-------------------------- Convert to Kelvin ----------------------------------

ConvertToKelvin:
if signC = "-" then
tempk = 27315 - temp
else
tempk = temp + 27315
endif
return

ConvertToFahrenheit:
if SignC = 160 then
SignF = 160
dummy = TempC * 18
TempF = div32 10
TempF = TempF + 3200
else
TempF = (tempc + 5000) * 900
TempF = DIV32 500
if TempC => 1778 and SignC = "-" then
TempF = TempF - 12200
SignF = "-"
else
TempF = 12200 - TempF
SignF = 160
endif
endif
return

Tom Estes
- 9th November 2007, 01:40
There isn't much difference between the Sensirion and 1wire CRC calculations. The Sensirion tests Bit 7 of the data and does a left shift for the next test bit whereas the 1wire version tests Bit 0 and does a right shift. They both use the same polynomial.

If you haven't downloaded Sensirion's CRC application note, you need to do that. In there it states the CRC covers the whole transmission (command and response bytes) without the acknowledge bits.

The CRC is initialized to the low 4 bits of the STATUS register. If you have not changed the STATUS register it defaults to zero meaning you should initialize SHTCRC to zero. If you have changed the status register then you need to read the application note carefully to see how to initialize SHTCRC (it has to be reversed).

Then send your command byte and the two received bytes to the CRC routine via variable SHTRxCRC. After receiving the CRC byte from the device it must be reversed. In PBP you can do this: Reversed_CRC = Received_CRC REV 8. Now compare Reversed_CRC and SHTCRC. They should be equal if the transmission was OK.

That's it....

CocaColaKid
- 9th November 2007, 16:09
Thank you very much for all your help Tom. Without your assistance I would still be out in the dark. Getting more familiar with this CRC checking thing as I go. This is my final code to do the CRC check. I simply compare CRC to CRCCalc and look for the match.



'--------- Calculate the CRC from Command Byte and Received Bytes --------------

GetSHTCRC:
CRCCalc = 0
DataByte = SensorCmd
gosub CalcSHTCRC
DataByte = SensorData.byte1
gosub CalcSHTCRC
databyte = SensorData.Byte0
gosub CalcSHTCRC
CRC = CRC REV 8
return

'--------------------- CRC Bit Calcuation Method -------------------------------

CalcSHTCRC:
for i = 0 to 7
DataBit = CRCCcalc.7 ^ DataByte.7
DataByte = DataByte << 1
if DataBit = 0 then ShiftSHT
CRCCcalc = CRCCcalc ^ $18

ShiftSHT:
CRCCcalc = CRCCcalc << 1
CRCCcalc.0 = DataBit
next i
return