340 lines
8.2 KiB
NASM
340 lines
8.2 KiB
NASM
; ***************************************************************************
|
|
; 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 SGP30_FLAGS_PRESENT_BIT = 7
|
|
.equ SGP30_FLAGS_DATAVALID_BIT = 6
|
|
|
|
|
|
.equ SGP30_CMD_INIT = 0x2003
|
|
.equ SGP30_CMD_MEASURE = 0x2008
|
|
|
|
.equ SGP30_VALUE_TVOC = 0x01
|
|
.equ SGP30_VALUE_CO2 = 0x02
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; data
|
|
|
|
.dseg
|
|
|
|
sgp30DataBegin:
|
|
sgp30Flags: .byte 1
|
|
sgp30LastCo2: .byte 2
|
|
sgp30LastTvoc: .byte 2
|
|
sgp30DataEnd:
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; SGP30_Init
|
|
;
|
|
|
|
SGP30_Init:
|
|
ldi xh, HIGH(sgp30DataBegin)
|
|
ldi xl, LOW(sgp30DataBegin)
|
|
clr r16
|
|
ldi r17, (sgp30DataEnd-sgp30DataBegin)
|
|
rcall Utils_FillSram
|
|
|
|
rjmp sg30InitIfNeeded
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; SGP30_Fini
|
|
;
|
|
|
|
SGP30_Fini:
|
|
sec
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine SGP30_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
|
|
|
|
SGP30_GetValue:
|
|
lds r18, sgp30Flags
|
|
andi r18, (1<<SGP30_FLAGS_DATAVALID_BIT)
|
|
breq SGP30_GetValue_clcRet
|
|
cpi r16, SGP30_VALUE_TVOC
|
|
breq SGP30_GetValue_retTvoc
|
|
cpi r16, SGP30_VALUE_CO2
|
|
breq SGP30_GetValue_retCo2
|
|
SGP30_GetValue_clcRet:
|
|
clc
|
|
ret
|
|
SGP30_GetValue_retTvoc:
|
|
lds r18, sgp30LastTvoc
|
|
lds r19, sgp30LastTvoc+1
|
|
ldi r20, 1
|
|
clr r21
|
|
rjmp SGP30_GetValue_secRet
|
|
SGP30_GetValue_retCo2:
|
|
lds r18, sgp30LastCo2
|
|
lds r19, sgp30LastCo2+1
|
|
ldi r20, 1
|
|
clr r21
|
|
SGP30_GetValue_secRet:
|
|
sec
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine sg30InitIfNeeded
|
|
;
|
|
; Expects interrupts being disabled!
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R16 (R17, R18, R22)
|
|
|
|
sg30InitIfNeeded:
|
|
lds r16, sgp30Flags
|
|
andi r16, (1<<SGP30_FLAGS_PRESENT_BIT)
|
|
breq sg30InitIfNeeded_doit
|
|
sec
|
|
ret
|
|
sg30InitIfNeeded_doit:
|
|
; check presence
|
|
rcall sgp30CheckPresence ; (R16, R17, R18, R22)
|
|
brcc sg30InitIfNeeded_error
|
|
; call init function
|
|
rcall sgp30Init
|
|
brcc sg30InitIfNeeded_error
|
|
lds r16, sgp30Flags
|
|
ori r16, (1<<SGP30_FLAGS_PRESENT_BIT)
|
|
sts sgp30Flags, r16
|
|
sec
|
|
ret
|
|
sg30InitIfNeeded_error:
|
|
clc
|
|
ret
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine sgp30CheckPresence
|
|
;
|
|
; Expects interrupts being disabled!
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R16 (R17, R18, R22)
|
|
|
|
sgp30CheckPresence:
|
|
ldi r16, (SGP30_ADDR*2) ; write access
|
|
rjmp twiCheckPresence ; (R16, R17, R18, R22)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine SGP30_EverySecond
|
|
;
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R16, R17, R18, R19, R20, R21, R22
|
|
|
|
SGP30_EverySecond:
|
|
rjmp SGP30_Measure ; (R16, R17, R18, R19, R20, R21, R22)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine SGP30_Measure
|
|
;
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R16, R17, R18, R19, R20, R21, R22
|
|
|
|
SGP30_Measure:
|
|
in r15, SREG
|
|
push r15
|
|
cli
|
|
lds r16, sgp30Flags
|
|
andi r16, (1<<SGP30_FLAGS_PRESENT_BIT)
|
|
breq SGP30_Measure_error
|
|
rcall sgp30Measure ; R19:R18=TVOC, R21:R20=CO2eq
|
|
brcc SGP30_Measure_error
|
|
lds r17, sgp30Flags
|
|
ori r17, (1<<SGP30_FLAGS_DATAVALID_BIT)
|
|
sts sgp30LastTvoc, r18
|
|
sts sgp30LastTvoc+1, r19
|
|
sts sgp30LastCo2, r20
|
|
sts sgp30LastCo2+1, r21
|
|
sts sgp30Flags, r17
|
|
SGP30_Measure_done:
|
|
pop r15
|
|
out SREG, r15
|
|
sec
|
|
ret
|
|
SGP30_Measure_error:
|
|
pop r15
|
|
out SREG, r15
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine sgp30Init
|
|
;
|
|
; 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.
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R14, R16 (R17, R18, R22)
|
|
|
|
sgp30Init:
|
|
; send request
|
|
ldi r20, HIGH(SGP30_CMD_INIT)
|
|
ldi r21, LOW(SGP30_CMD_INIT)
|
|
rcall sgp30SendCommand ; (R16, R20, R21, R17, R18, R22)
|
|
brcc sgp30Init_error
|
|
; no response expected, just STOP
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
sgp30Init_error:
|
|
rcall twiStop ; (R22)
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine sgp30Measure
|
|
;
|
|
; 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.
|
|
;
|
|
; @return CFLAG set if okay, clear on error
|
|
; @return r19:r18 TVOC
|
|
; @return r21:r20 CO2 equivalent
|
|
; @clobbers R14, R16, R18, R19, R22
|
|
|
|
sgp30Measure:
|
|
ldi r20, HIGH(SGP30_CMD_MEASURE)
|
|
ldi r21, LOW(SGP30_CMD_MEASURE)
|
|
rcall sgp30SendCommand ; (R16, R20, R21, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
|
|
; read response
|
|
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
mov r21, r16 ; MSByte
|
|
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
mov r20, r16 ; LSByte (CO2)
|
|
rcall twiReceiveByte ; R16=CRC8, no ACK (R16, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
|
|
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
mov r19, r16 ; MSByte
|
|
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
|
brcc sgp30Measure_error
|
|
mov r18, r16 ; LSByte
|
|
push r18
|
|
rcall twiReceiveByte ; R16=CRC8, no ACK (R16, R17, R18, R22)
|
|
pop r18
|
|
brcc sgp30Measure_error
|
|
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
sgp30Measure_error:
|
|
rcall twiStop ; (R22)
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine sgp30SendCommand
|
|
;
|
|
; 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.
|
|
;
|
|
; @param R20 1st command byte
|
|
; @param R21 2nd command byte
|
|
; @return CFLAG set if okay, clear on error
|
|
; @clobbers R16, R20, R21 (R17, R18, R22)
|
|
|
|
sgp30SendCommand:
|
|
; send request
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (SGP30_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
|
brcc sgp30SendCommand_error
|
|
mov r16, r20
|
|
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
|
brcc sgp30SendCommand_error
|
|
mov r16, r21
|
|
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
|
brcc sgp30SendCommand_error
|
|
|
|
; receive response
|
|
ldi r20, 15 ; wait max 15ms
|
|
sgp30SendCommand_loop1:
|
|
ldi r21, 10 ; 1ms
|
|
sgp30SendCommand_loop2: ; (R22)
|
|
rcall twiRestart
|
|
ldi r16, (SGP30_ADDR*2)+1 ; read access
|
|
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
|
brcs sgp30SendCommand_gotResponse ; chip responds, receive values
|
|
rcall Utils_WaitFor50MicroSecs ; wait for 100usecs total
|
|
rcall Utils_WaitFor50MicroSecs
|
|
dec r21
|
|
brne sgp30SendCommand_loop2
|
|
dec r20
|
|
brne sgp30SendCommand_loop1
|
|
rjmp sgp30SendCommand_error
|
|
sgp30SendCommand_gotResponse:
|
|
sec
|
|
ret
|
|
sgp30SendCommand_error:
|
|
rcall twiStop ; (R22)
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|