Files
aqhomecontrol/avr/modules/sgp40/main.asm
2025-05-14 23:18:26 +02:00

213 lines
4.9 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 SGP40_FLAGS_PRESENT_BIT = 7
.equ SGP40_FLAGS_DATAVALID_BIT = 6
.equ SGP40_CMD_MEASURE = 0x260f
; ***************************************************************************
; data
.dseg
sgp40DataBegin:
sgp40Flags: .byte 1
sgp40LastValue: .byte 2
sgp40DataEnd:
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; SGP40_Init
;
SGP40_Init:
ldi xh, HIGH(sgp40DataBegin)
ldi xl, LOW(sgp40DataBegin)
clr r16
ldi r17, (sgp40DataEnd-sgp40DataBegin)
rcall Utils_FillSram
; check presence
rcall sgp40CheckPresence
brcc SGP40_Init_error
lds r16, sgp40Flags
ori r16, (1<<SGP40_FLAGS_PRESENT_BIT)
sts sgp40Flags, r16
sec
ret
SGP40_Init_error:
clc
ret
; @end
; ---------------------------------------------------------------------------
; SGP40_Fini
;
SGP40_Fini:
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine SGP40_GetValue @global
;
; @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
SGP40_GetValue:
lds r16, sgp40Flags
andi r16, (1<<SGP40_FLAGS_DATAVALID_BIT)
brne SGP40_GetValue_gotValue
clc
ret
SGP40_GetValue_gotValue:
lds r18, sgp40LastValue
lds r19, sgp40LastValue+1
ldi r20, 1
clr r21
sec
ret
; @end
; ---------------------------------------------------------------------------
; @routine sgp40CheckPresence
;
; Expects interrupts being disabled!
;
; @return CFLAG set if okay, clear on error
; @clobbers R16 (R17, R18, R22)
sgp40CheckPresence:
ldi r16, (SGP40_ADDR*2)+1 ; read access
rjmp twiCheckPresence ; (R16, R17, R18, R22)
; @end
SGP40_MeasureRawSignal:
in r15, SREG
push r15
cli
lds r17, sgp40Flags
sbrs r17, SGP40_FLAGS_PRESENT_BIT ; investigate PRESENT BIT
rjmp SGP40_MeasureRawSignal_error ; jmp if PRESENT bit clear
rcall sgp40Measure ; R19:18=value
brcc SGP40_MeasureRawSignal_error
lds r17, sgp40Flags
ori r17, (1<<SGP40_FLAGS_DATAVALID_BIT)
sts sgp40LastValue, r18
sts sgp40LastValue+1, r19
sts sgp40Flags, r17
SGP40_MeasureRawSignal_done:
pop r15
out SREG, r15
sec
ret
SGP40_MeasureRawSignal_error:
pop r15
out SREG, r15
clc
ret
; @end
; ---------------------------------------------------------------------------
; @routine sgp40Measure
;
; 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 received raw value
; @clobbers R14, R16, R18, R19, R22
sgp40Measure:
; send request
rcall twiStart ; (R22)
ldi r16, (SGP40_ADDR*2) ; write access
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc sgp40Measure_error
ldi zl, LOW(sgp40FlashDataCmdMeasureDefault*2)
ldi zh, HIGH(sgp40FlashDataCmdMeasureDefault*2)
ldi r19, 8
rcall twiSendFromFlashExpectAck
brcc sgp40Measure_error ; no ACK or other error
; receive response
ldi r16, 200
mov r14, r16
sgp40Measure_loop: ; (R22)
rcall twiRestart
ldi r16, (SGP40_ADDR*2)+1 ; read access
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcs sgp40Measure_gotValue ; chip responds, receive values
dec r14
breq sgp40Measure_error ; timeout
rcall Utils_WaitFor50MicroSecs ; wait for 100usecs total
rcall Utils_WaitFor50MicroSecs
rjmp sgp40Measure_loop
sgp40Measure_gotValue:
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
brcc sgp40Measure_error
mov r19, r16 ; MSByte
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
brcc sgp40Measure_error
mov r18, r16 ; LSByte
push r18
rcall twiReceiveByte ; R16=CRC8, no ACK (R16, R17, R18, R22)
pop r18
brcc sgp40Measure_error
rcall twiStop ; (R22)
sec
ret
sgp40Measure_error:
rcall twiStop ; (R22)
clc
ret
; @end
sgp40FlashDataCmdMeasureDefault: .db 0x26, 0x0f, 0x80, 0x00, 0xa2, 0x66, 0x66, 0x93