; *************************************************************************** ; copyright : (C) 2023 by Martin Preuss ; email : martin@libchipcard.de ; ; *************************************************************************** ; * This file is part of the project "AqHome". * ; * Please see toplevel file COPYING of that project for license details. * ; *************************************************************************** ; *************************************************************************** ; 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_BEGIN: ; --------------------------------------------------------------------------- ; 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 #if 0 ; --------------------------------------------------------------------------- ; 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 #endif ; --------------------------------------------------------------------------- ; 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 SI7021_SendTemp: lds r16, si7021Flags andi r16, SI7021_FLAGS_TEMP_VALID brne SI7021_SendTemp_haveValue sec ret SI7021_SendTemp_haveValue: ldi r16, 0xff ; destination address ldi r17, VALUE_ID_TEMP1 ; value id ldi r22, AQHOME_VALUETYPE_TEMP lds r18, si7021LastTemp ; value lds r19, si7021LastTemp+1 ldi r20, 100 ; denominator clr r21 rjmp SI7021_SendValue SI7021_SendHumidity: lds r16, si7021Flags andi r16, SI7021_FLAGS_HUM_VALID brne SI7021_SendHumidity_haveValue clc ret SI7021_SendHumidity_haveValue: ldi r16, 0xff ; destination address ldi r17, VALUE_ID_HUM1 ; value id ldi r22, AQHOME_VALUETYPE_HUMIDITY lds r18, si7021LastHumidity ; value lds r19, si7021LastHumidity+1 ldi r20, 1 ; denominator clr r21 rjmp SI7021_SendValue SI7021_SendValue: ldi xl, LOW(com2SendBuffer) ldi xh, HIGH(com2SendBuffer) rcall CPRO_WriteValue rjmp COM2_SendPacket SI7021_END: .equ MODULE_SIZE_SI7021 = SI7021_END-SI7021_BEGIN