; *************************************************************************** ; copyright : (C) 2025 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_BIT = 7 .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 .equ SI7021_VALUE_TEMP = 0x01 .equ SI7021_VALUE_HUMIDITY = 0x02 ; *************************************************************************** ; 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_MeasureTemp: in r15, SREG push r15 cli lds r17, si7021Flags sbrs r17, SI7021_FLAGS_PRESENT_BIT ; investigate PRESENT BIT rjmp SI7021_MeasureTemp_error ; jmp if PRESENT bit clear push r17 rcall si7021MeasureTemp pop r17 brcc SI7021_MeasureTemp_error ori r17, SI7021_FLAGS_TEMP_VALID sts si7021Flags, r17 rcall si7021CalcTemp sts si7021LastTemp, r18 sts si7021LastTemp+1, r19 SI7021_MeasureTemp_done: pop r15 out SREG, r15 sec ret SI7021_MeasureTemp_error: pop r15 out SREG, r15 clc ret ; @end SI7021_MeasureHumidity: in r15, SREG push r15 cli lds r17, si7021Flags sbrs r17, SI7021_FLAGS_PRESENT_BIT ; investigate PRESENT BIT rjmp SI7021_MeasureHumidity_error ; jmp if PRESENT bit clear push r17 rcall si7021MeasureHumidity pop r17 brcc SI7021_MeasureHumidity_error ori r17, SI7021_FLAGS_HUM_VALID sts si7021Flags, r17 rcall si7021CalcHumidity ; sts si7021LastHumidity, r18 sts si7021LastHumidity+1, r19 SI7021_MeasureHumidity_done: pop r15 out SREG, r15 sec ret SI7021_MeasureHumidity_error: pop r15 out SREG, r15 clc ret ; @end ; --------------------------------------------------------------------------- ; si7021CheckPresence ; ; Expects interrupts being disabled! ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear on error ; USED: si7021CheckPresence: ldi r16, (SI7021_ADDR*2)+1 rjmp twiCheckPresence ; --------------------------------------------------------------------------- ; 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) brcc si7021MeasureAny_error ; no ACK or other error 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 rcall Utils_WaitFor50MicroSecs ; wait for 100usecs total rcall Utils_WaitFor50MicroSecs 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 Utils_Mulu16x16_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 Utils_Mulu16x16_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 ; --------------------------------------------------------------------------- ; @routine SI7021_GetValue @global ; ; @param R16 value to get (SI7021_VALUE_TEMP, SI7021_VALUE_HUMIDITY) ; @return CFLAG set if value available, cleared otherwise ; @return R19:R18 value ; @return R21:R20 denom (e.g. 100, meaning value must be divided by 100) ; @clobbers R16 SI7021_GetValue: cpi r16, SI7021_VALUE_TEMP breq SI7021_GetValue_temp cpi r16, SI7021_VALUE_HUMIDITY breq SI7021_GetValue_hum SI7021_GetValue_clcRet: clc ret SI7021_GetValue_temp: lds r16, si7021Flags andi r16, SI7021_FLAGS_TEMP_VALID breq SI7021_GetValue_clcRet lds r18, si7021LastTemp ; value lds r19, si7021LastTemp+1 ldi r20, 100 ; denominator rjmp SI7021_GetValue_finishValue SI7021_GetValue_hum: lds r16, si7021Flags andi r16, SI7021_FLAGS_HUM_VALID breq SI7021_GetValue_clcRet lds r18, si7021LastHumidity ; value lds r19, si7021LastHumidity+1 ldi r20, 1 ; denominator SI7021_GetValue_finishValue: clr r21 sec ret ; @end SI7021_END: .equ MODULE_SIZE_SI7021 = SI7021_END-SI7021_BEGIN