Added module for SI7021 temp/humidity sensor.
This commit is contained in:
438
avr/si7021.asm
Normal file
438
avr/si7021.asm
Normal file
@@ -0,0 +1,438 @@
|
||||
; ***************************************************************************
|
||||
; SI7021 module
|
||||
; (c) 2023 Martin Preuss
|
||||
;
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; defines
|
||||
|
||||
.equ SI7021_FLAGS_PRESENT = 0x80
|
||||
.equ SI7021_FLAGS_TEMP_VALID = 0x40
|
||||
.equ SI7021_FLAGS_HUM_VALID = 0x20
|
||||
.equ SI7021_FLAGS_LASTWASTEMP = 0x10
|
||||
.equ SI7021_FLAGS_ERROR_MASK = 0x07
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; data
|
||||
|
||||
.dseg
|
||||
|
||||
si7021DataBegin:
|
||||
si7021Flags: .byte 1
|
||||
si7021FirmwareRevision: .byte 1
|
||||
si7021LastTemp: .byte 2
|
||||
si7021LastHumidity: .byte 2
|
||||
si7021DataEnd:
|
||||
|
||||
|
||||
|
||||
; ***************************************************************************
|
||||
; code
|
||||
|
||||
.cseg
|
||||
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; SI7021_Init
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
SI7021_Init:
|
||||
ldi xh, HIGH(si7021DataBegin)
|
||||
ldi xl, LOW(si7021DataBegin)
|
||||
clr r16
|
||||
ldi r17, (si7021DataEnd-si7021DataBegin)
|
||||
rcall Utils_FillSram
|
||||
; check presence
|
||||
rcall si7021CheckPresence
|
||||
brcc SI7021_Init_error
|
||||
lds r16, si7021Flags
|
||||
ori r16, SI7021_FLAGS_PRESENT
|
||||
sts si7021Flags, r16
|
||||
; get firmware revision
|
||||
; rcall si7021ReadFirmwareRevision
|
||||
; brcc SI7021_Init_error
|
||||
; sts si7021FirmwareRevision, r16
|
||||
sec
|
||||
ret
|
||||
SI7021_Init_error:
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; SI7021_Fini
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
SI7021_Fini:
|
||||
sec
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; SI7021_PeriodicMeasurement
|
||||
;
|
||||
; Call this routine periodically to take measurements.
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
SI7021_PeriodicMeasurement:
|
||||
in r15, SREG
|
||||
push r15
|
||||
cli
|
||||
lds r17, si7021Flags
|
||||
mov r16, r17
|
||||
andi r16, SI7021_FLAGS_LASTWASTEMP
|
||||
brne si7021PeriodicMeasurement_hum
|
||||
ori r17, SI7021_FLAGS_LASTWASTEMP
|
||||
sts si7021Flags, r17
|
||||
push r17
|
||||
rcall si7021MeasureTemp
|
||||
pop r17
|
||||
brcc si7021PeriodicMeasurement_error
|
||||
ori r17, SI7021_FLAGS_TEMP_VALID
|
||||
sts si7021Flags, r17
|
||||
rcall si7021CalcTemp ; calculate temp*100 from sensor value
|
||||
sts si7021LastTemp, r18
|
||||
sts si7021LastTemp+1, r19
|
||||
rjmp si7021PeriodicMeasurement_done
|
||||
si7021PeriodicMeasurement_hum:
|
||||
andi r17, ~SI7021_FLAGS_LASTWASTEMP
|
||||
sts si7021Flags, r17
|
||||
push r17
|
||||
rcall si7021MeasureHumidity
|
||||
pop r17
|
||||
brcc si7021PeriodicMeasurement_error
|
||||
ori r17, SI7021_FLAGS_HUM_VALID
|
||||
sts si7021Flags, r17
|
||||
rcall si7021CalcHumidity
|
||||
sts si7021LastHumidity, r18
|
||||
sts si7021LastHumidity+1, r19
|
||||
si7021PeriodicMeasurement_done:
|
||||
pop r15
|
||||
out SREG, r15
|
||||
sec
|
||||
ret
|
||||
si7021PeriodicMeasurement_error:
|
||||
pop r15
|
||||
out SREG, r15
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021CheckPresence
|
||||
;
|
||||
; Expects interrupts being disabled!
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
si7021CheckPresence:
|
||||
rcall twiStart
|
||||
ldi r16, (SI7021_ADDR*2)+1
|
||||
rcall twiSendByte
|
||||
brcc si7021CheckPresence_notfound
|
||||
rcall twiStop
|
||||
sec
|
||||
ret
|
||||
|
||||
si7021CheckPresence_notfound:
|
||||
rcall twiStop
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021ReadFirmwareRevision
|
||||
;
|
||||
; Expects interrupts being disabled!
|
||||
; Currently doesn't work (my SI7021 doesn't accept the command).
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; - R16: firmware revision (0xff: version 1.0, 0x20: version 2.0)
|
||||
; USED:
|
||||
|
||||
si7021ReadFirmwareRevision:
|
||||
rcall twiStart
|
||||
ldi r16, (SI7021_ADDR*2) ; write access
|
||||
rcall twiSendByteExpectAck
|
||||
brcc si7021ReadFirmwareRevision_error1
|
||||
ldi r16, 0x84
|
||||
rcall twiSendByteExpectAck
|
||||
brcc si7021ReadFirmwareRevision_error2
|
||||
ldi r16, 0xb8
|
||||
rcall twiSendByteExpectAck
|
||||
brcc si7021ReadFirmwareRevision_error3
|
||||
rcall twiRestart
|
||||
ldi r16, (SI7021_ADDR*2)+1 ; read access
|
||||
rcall twiSendByteExpectAck
|
||||
brcc si7021ReadFirmwareRevision_error4
|
||||
rcall twiReceiveByte ; don't send ACK
|
||||
brcc si7021ReadFirmwareRevision_error5
|
||||
rcall twiStop
|
||||
sec
|
||||
ret
|
||||
|
||||
si7021ReadFirmwareRevision_error1:
|
||||
ldi r16, 1
|
||||
rcall si7021SetError
|
||||
rjmp si7021ReadFirmwareRevision_error
|
||||
si7021ReadFirmwareRevision_error2:
|
||||
ldi r16, 2
|
||||
rcall si7021SetError
|
||||
rjmp si7021ReadFirmwareRevision_error
|
||||
si7021ReadFirmwareRevision_error3:
|
||||
ldi r16, 3
|
||||
rcall si7021SetError
|
||||
rjmp si7021ReadFirmwareRevision_error
|
||||
si7021ReadFirmwareRevision_error4:
|
||||
ldi r16, 4
|
||||
rcall si7021SetError
|
||||
rjmp si7021ReadFirmwareRevision_error
|
||||
si7021ReadFirmwareRevision_error5:
|
||||
ldi r16, 5
|
||||
rcall si7021SetError
|
||||
rjmp si7021ReadFirmwareRevision_error
|
||||
|
||||
si7021ReadFirmwareRevision_error:
|
||||
rcall twiStop
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021MeasureTemp
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
si7021MeasureTemp:
|
||||
ldi r16, 0xf3
|
||||
rjmp si7021MeasureAny
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021MeasureHumidity
|
||||
;
|
||||
; IN:
|
||||
; - nothing
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED:
|
||||
|
||||
si7021MeasureHumidity:
|
||||
ldi r16, 0xf5
|
||||
rjmp si7021MeasureAny
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021MeasureAny
|
||||
;
|
||||
; Sends the given command to the sensor and reads the result.
|
||||
; Synchronization is done by sending re-start sequences until the sensor answers with
|
||||
; the value.
|
||||
; IN:
|
||||
; - R16: command to send
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED: R14, R16, R18, R19
|
||||
|
||||
si7021MeasureAny:
|
||||
rcall twiStart ; (R22)
|
||||
push r16
|
||||
ldi r16, (SI7021_ADDR*2) ; write access
|
||||
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
||||
pop r16
|
||||
brcc si7021MeasureAny_error
|
||||
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
||||
|
||||
ldi r16, 200
|
||||
mov r14, r16
|
||||
si7021MeasureAny_loop: ; (R22)
|
||||
rcall twiRestart
|
||||
ldi r16, (SI7021_ADDR*2)+1 ; read access
|
||||
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
||||
brcs si7021MeasureAny_gotValue ; chip responds, receive values
|
||||
dec r14
|
||||
breq si7021MeasureAny_error ; timeout
|
||||
Utils_WaitNanoSecs 100000, 0, r22
|
||||
rjmp si7021MeasureAny_loop
|
||||
|
||||
si7021MeasureAny_gotValue:
|
||||
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
||||
brcc si7021MeasureAny_error
|
||||
mov r19, r16 ; MSByte
|
||||
rcall twiReceiveByte ; no ACK (R16, R17, R18, R22)
|
||||
brcc si7021MeasureAny_error
|
||||
mov r18, r16
|
||||
rcall twiStop ; (R22)
|
||||
ldi r16, 0
|
||||
rcall si7021SetError ; (none)
|
||||
sec
|
||||
ret
|
||||
si7021MeasureAny_error:
|
||||
rcall twiStop ; (R22)
|
||||
clc
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021SetError
|
||||
;
|
||||
; Set error code in flags.
|
||||
; IN:
|
||||
; - R16: error code to set (0-7)
|
||||
; OUT:
|
||||
; - CFLAG: set if okay, clear on error
|
||||
; USED: none
|
||||
|
||||
|
||||
si7021SetError:
|
||||
push r17
|
||||
lds r17, si7021Flags
|
||||
andi r17, ~SI7021_FLAGS_ERROR_MASK
|
||||
or r17, r16
|
||||
sts si7021Flags, r17
|
||||
pop r17
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021CalcTemp
|
||||
;
|
||||
; Calculates temperatur * 100.
|
||||
; Uses formula from specs: temp=(175.72*TEMP_CODE/65536)-46.85.
|
||||
;
|
||||
; IN:
|
||||
; - R19:R18: Temperature value read from sensor
|
||||
; OUT:
|
||||
; - R19:R18: calculated temperature(Celsius) * 100
|
||||
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
|
||||
|
||||
si7021CalcTemp:
|
||||
mov r20, r18
|
||||
mov r21, r19
|
||||
ldi r23, HIGH(17572)
|
||||
ldi r22, LOW(17572)
|
||||
rcall si7021Mulu16x16_32 ; result is in R19:R18:R17:R16, we only use R19-R18 -> /65536
|
||||
ldi r16, LOW(4685)
|
||||
ldi r17, HIGH(4685)
|
||||
sub r18, r16
|
||||
sbc r19, r17
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021CalcHumidity
|
||||
;
|
||||
; Calculates humidity in percent.
|
||||
; Uses formula from specs: rel humidity=(125*HUMIDITY_CODE/65536)-6.
|
||||
;
|
||||
; IN:
|
||||
; - R19:R18: Humidity value read from sensor
|
||||
; OUT:
|
||||
; - R19:R18: calculated relative humidity
|
||||
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
|
||||
|
||||
si7021CalcHumidity:
|
||||
mov r20, r18
|
||||
mov r21, r19
|
||||
clr r23
|
||||
ldi r22, 125
|
||||
rcall si7021Mulu16x16_32 ; result is in R19:R18:R17:R16, we only use R19-R18 -> /65536
|
||||
ldi r16, 6
|
||||
clr r17
|
||||
sub r18, r16
|
||||
sbc r19, r17
|
||||
ret
|
||||
|
||||
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; si7021Mulu16x16_32
|
||||
;
|
||||
; Multiplies two unsigned 16 bit values resulting in one 32 bit value.
|
||||
; This is a rather simple but reasonable fast routine working just like you would
|
||||
; when doing multiplications with pen and paper.
|
||||
; TODO: adapt for signed values
|
||||
;
|
||||
; IN:
|
||||
; - R21:R20: 16 bit value A
|
||||
; - R23:R22: 16 bit value B
|
||||
; OUT:
|
||||
; - R19:R18:R17:R16: 32 bit result
|
||||
; USED: R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26
|
||||
; R19:R18:R17:R16 = R21:R20 * R23:R22
|
||||
; R19:R18:R17:R16 = R25:R24:R21:R20 * R23:R22
|
||||
si7021Mulu16x16_32:
|
||||
clr r19
|
||||
clr r18
|
||||
clr r17
|
||||
clr r16
|
||||
clr r25
|
||||
clr r24
|
||||
ldi r26, 16 ; 16 bit multiplicator
|
||||
si7021Muls16x16_32_loop:
|
||||
lsr r23
|
||||
ror r22
|
||||
brcc si7021Muls16x16_32_noadd ; current digit in B is 0, don't add shifted A to result
|
||||
add r16, r22
|
||||
adc r17, r23
|
||||
adc r18, r24
|
||||
adc r19, r25
|
||||
; brcs si7021Muls16x16_32_overflow ; can't happen
|
||||
si7021Muls16x16_32_noadd:
|
||||
dec r26
|
||||
breq si7021Muls16x16_32_done
|
||||
lsl r20
|
||||
rol r21
|
||||
rol r24
|
||||
rol r25
|
||||
; brcs si7021Muls16x16_32_overflow ; can't happen
|
||||
rjmp si7021Muls16x16_32_loop
|
||||
si7021Muls16x16_32_done:
|
||||
clc
|
||||
ret
|
||||
;si7021Muls16x16_32_overflow: ; never reached. Multiplying 2 16 bit values can't overflow 32 bit
|
||||
; sec
|
||||
; ret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user