diff --git a/avr/modules/si7021/0BUILD b/avr/modules/si7021/0BUILD index febd367..e93f9da 100644 --- a/avr/modules/si7021/0BUILD +++ b/avr/modules/si7021/0BUILD @@ -4,6 +4,7 @@ main.asm + main2.asm diff --git a/avr/modules/si7021/main.asm b/avr/modules/si7021/main.asm index 8f146c8..6b1b5fc 100644 --- a/avr/modules/si7021/main.asm +++ b/avr/modules/si7021/main.asm @@ -452,47 +452,6 @@ si7021Muls16x16_32_done: -; --------------------------------------------------------------------------- -; @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_SendTemp: lds r16, si7021Flags andi r16, SI7021_FLAGS_TEMP_VALID diff --git a/avr/modules/si7021/main2.asm b/avr/modules/si7021/main2.asm new file mode 100644 index 0000000..44ae478 --- /dev/null +++ b/avr/modules/si7021/main2.asm @@ -0,0 +1,440 @@ +; *************************************************************************** +; 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 si7021MeasureHumidity + pop r17 + brcc SI7021_MeasureTemp_error + ori r17, SI7021_FLAGS_TEMP_VALID + sts si7021Flags, r17 + rcall si7021CalcHumidity + sts si7021LastHumidity, r18 + sts si7021LastHumidity+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 si7021CalcTemp ; calculate temp*100 from sensor value + sts si7021LastTemp, r18 + sts si7021LastTemp+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: + rcall twiStart + ldi r16, (SI7021_ADDR*2)+1 + rcall twiSendByte + brcc si7021CheckPresence_notfound + rcall twiStop + sec + ret + +si7021CheckPresence_notfound: + 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) + 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 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 + + + +; --------------------------------------------------------------------------- +; @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 + +