428 lines
9.3 KiB
NASM
428 lines
9.3 KiB
NASM
; ***************************************************************************
|
|
; 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 CCS811_FLAGS_ACTIVATED = 0x80
|
|
.equ CCS811_FLAGS_RESETTED = 0x40
|
|
.equ CCS811_FLAGS_VALIDDATA = 0x20
|
|
|
|
.equ CCS811_VALUE_TVOC = 0x01
|
|
.equ CCS811_VALUE_CO2 = 0x02
|
|
|
|
.equ CCS811_WAITMS_AFTER_RESET = 50
|
|
.equ CCS811_WAITMS_AFTER_START = 50
|
|
|
|
.equ CCS811_REG_STATUS = 0x00
|
|
.equ CCS811_REG_MEASMODE = 0x01
|
|
.equ CCS811_REG_DATA = 0x02
|
|
.equ CCS811_REG_APP_START = 0xf4
|
|
.equ CCS811_REG_SWRESET = 0xff
|
|
|
|
.equ CCS811_STATUS_FWMODE_BIT = 7
|
|
.equ CCS811_STATUS_APPVALID_BIT = 4
|
|
.equ CCS811_STATUS_DATAREADY_BIT = 3
|
|
.equ CCS811_STATUS_ERROR_BIT = 0
|
|
|
|
.equ CCS811_MEASUREMODE_DM2_BIT = 6
|
|
.equ CCS811_MEASUREMODE_DM1_BIT = 5
|
|
.equ CCS811_MEASUREMODE_DM0_BIT = 4
|
|
|
|
.equ CCS811_MEASUREMODE = (0<<CCS811_MEASUREMODE_DM2_BIT) | (1<<CCS811_MEASUREMODE_DM1_BIT) | (1<<CCS811_MEASUREMODE_DM0_BIT)
|
|
;.equ CCS811_MEASUREMODE = (0<<CCS811_MEASUREMODE_DM2_BIT) | (1<<CCS811_MEASUREMODE_DM1_BIT) | (0<<CCS811_MEASUREMODE_DM0_BIT)
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; data
|
|
|
|
.dseg
|
|
|
|
ccs811DataBegin:
|
|
ccs811Flags: .byte 1
|
|
ccs811ResponseData: .byte 5
|
|
ccs811DataEnd:
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
CCS811_BEGIN:
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; CCS811_Init
|
|
;
|
|
; IN:
|
|
; - nothing
|
|
; OUT:
|
|
; - CFLAG: set if okay, clear on error
|
|
; USED:
|
|
|
|
CCS811_Init:
|
|
ldi xh, HIGH(ccs811DataBegin)
|
|
ldi xl, LOW(ccs811DataBegin)
|
|
clr r16
|
|
ldi r17, (ccs811DataEnd-ccs811DataBegin)
|
|
rcall Utils_FillSram
|
|
|
|
; check for fw mode, valid app
|
|
rcall ccs811ReadStatus
|
|
brcc CCS811_Init_error
|
|
|
|
ldi r17, (1<<CCS811_STATUS_FWMODE_BIT) ; already in FW mode?
|
|
and r17, r16
|
|
breq CCS811_Init_startApp
|
|
rcall ccs811Reset
|
|
brcc CCS811_Init_error
|
|
|
|
lds r17, ccs811Flags
|
|
ori r17, CCS811_FLAGS_RESETTED
|
|
sts ccs811Flags, r17
|
|
|
|
ldi r16, CCS811_WAITMS_AFTER_RESET
|
|
rcall ccs811WaitMs
|
|
|
|
rcall ccs811ReadStatus
|
|
brcc CCS811_Init_error
|
|
|
|
CCS811_Init_startApp:
|
|
; check for valid app
|
|
andi r16, (1<<CCS811_STATUS_APPVALID_BIT)
|
|
breq CCS811_Init_error ; no valid app
|
|
|
|
; start app
|
|
rcall ccs811StartApp
|
|
brcc CCS811_Init_error
|
|
|
|
ldi r16, CCS811_WAITMS_AFTER_START
|
|
rcall ccs811WaitMs
|
|
|
|
rcall ccs811ReadStatus
|
|
brcc CCS811_Init_error
|
|
andi r16, (1<<CCS811_STATUS_FWMODE_BIT) ; in firmware mode?
|
|
breq CCS811_Init_error ; no, error
|
|
|
|
; set measurement mode
|
|
ldi r16, CCS811_MEASUREMODE
|
|
rcall ccs811SetMeasureMode
|
|
brcc CCS811_Init_error
|
|
|
|
lds r17, ccs811Flags
|
|
ori r17, CCS811_FLAGS_ACTIVATED
|
|
sts ccs811Flags, r17
|
|
sec
|
|
ret
|
|
CCS811_Init_error:
|
|
clc
|
|
ret
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; CCS811_Fini
|
|
;
|
|
; IN:
|
|
; - nothing
|
|
; OUT:
|
|
; - CFLAG: set if okay, clear on error
|
|
; USED:
|
|
|
|
CCS811_Fini:
|
|
sec
|
|
ret
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; CCS811_OnTimer
|
|
;
|
|
; Call this routine periodically to take measurements.
|
|
; IN:
|
|
; - nothing
|
|
; OUT:
|
|
; - CFLAG: set if okay, clear on error
|
|
; USED:
|
|
|
|
CCS811_OnEveryMinute:
|
|
in r15, SREG
|
|
push r15
|
|
cli
|
|
lds r16, ccs811Flags
|
|
andi r16, CCS811_FLAGS_ACTIVATED
|
|
breq CCS811_OnTimer_ret
|
|
|
|
lds r16, ccs811Flags
|
|
andi r16, ~CCS811_FLAGS_VALIDDATA
|
|
sts ccs811Flags, r16
|
|
rcall ccs811ReadMeasurement
|
|
brcc CCS811_OnTimer_ret
|
|
lds r16, ccs811ResponseData+4
|
|
andi r16, (1<<CCS811_STATUS_DATAREADY_BIT)
|
|
breq CCS811_OnTimer_ret ; jmp if data not ready
|
|
lds r16, ccs811Flags
|
|
ori r16, CCS811_FLAGS_VALIDDATA
|
|
sts ccs811Flags, r16
|
|
CCS811_OnTimer_ret:
|
|
pop r15
|
|
out SREG, r15
|
|
ret
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; ccs811CheckPresence
|
|
;
|
|
; Expects interrupts being disabled!
|
|
;
|
|
; IN:
|
|
; - nothing
|
|
; OUT:
|
|
; - CFLAG: set if okay, clear on error
|
|
; USED:
|
|
|
|
ccs811CheckPresence:
|
|
rcall twiStart
|
|
ldi r16, (CCS811_ADDR*2)+1
|
|
rcall twiSendByte
|
|
brcc ccs811CheckPresence_notfound
|
|
rcall twiStop
|
|
sec
|
|
ret
|
|
|
|
ccs811CheckPresence_notfound:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
|
|
|
|
ccs811ReadStatus:
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811ReadStatus_error
|
|
ldi r16, CCS811_REG_STATUS
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811ReadStatus_error
|
|
rcall twiRestart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2)+1 ; read access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811ReadStatus_error
|
|
rcall twiReceiveByte ; don't send ACK
|
|
brcc ccs811ReadStatus_error
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
ccs811ReadStatus_error:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
ccs811StartApp:
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811StartApp_error
|
|
ldi r16, CCS811_REG_APP_START
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811StartApp_error
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
ccs811StartApp_error:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
; @clobbers r16, r17, r22
|
|
|
|
ccs811SetMeasureMode:
|
|
mov r19, r16
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811SetMeasureMode_error
|
|
ldi r16, CCS811_REG_MEASMODE
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811SetMeasureMode_error
|
|
mov r16, r19
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811SetMeasureMode_error
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
ccs811SetMeasureMode_error:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
ccs811Reset:
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
ldi r16, CCS811_REG_SWRESET
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
ldi r16, 0x11
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
ldi r16, 0xe5
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
ldi r16, 0x72
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
ldi r16, 0x8a
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811Reset_error
|
|
rcall twiStop ; (R22)
|
|
sec
|
|
ret
|
|
ccs811Reset_error:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
ccs811ReadMeasurement:
|
|
ldi xh, HIGH(ccs811ResponseData)
|
|
ldi xl, LOW(ccs811ResponseData)
|
|
ldi r16, CCS811_REG_DATA
|
|
ldi r17, 5
|
|
rjmp ccs811ReadData
|
|
; @end
|
|
|
|
|
|
|
|
; @param r16 reg to read
|
|
; @param r17 number of bytes to read
|
|
; @param X pointer to buffer to receive data
|
|
; @return CFLAG set if okay, cleared on error
|
|
; @return r16 number of bytes received if CFLAG set
|
|
|
|
ccs811ReadData:
|
|
mov r20, r16
|
|
mov r19, r17
|
|
rcall twiStart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2) ; write access
|
|
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
|
|
brcc ccs811ReadData_error
|
|
mov r16, r20
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811ReadData_error
|
|
rcall twiRestart ; (R22)
|
|
ldi r16, (CCS811_ADDR*2)+1 ; read access
|
|
rcall twiSendByteExpectAck
|
|
brcc ccs811ReadData_error
|
|
|
|
clr r20
|
|
ccs811ReadData_loop1:
|
|
cpi r19, 1
|
|
breq ccs811ReadData_recvLast
|
|
rcall twiReceiveByteSendAck ; (R16, R17, R18, R22)
|
|
rjmp ccs811ReadData_recvd
|
|
ccs811ReadData_recvLast:
|
|
rcall twiReceiveByte ; don't send ACK (R16, R17, R18, R22)
|
|
ccs811ReadData_recvd:
|
|
brcc ccs811ReadData_error
|
|
st X+, r16
|
|
inc r20
|
|
dec r19
|
|
brne ccs811ReadData_loop1
|
|
rcall twiStop ; (R22)
|
|
mov r16, r20
|
|
sec
|
|
ret
|
|
ccs811ReadData_error:
|
|
rcall twiStop
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine CCS811_GetValue @global
|
|
;
|
|
; @param R16 value to get (CCS811_VALUE_TVOC, CCS811_VALUE_CO2)
|
|
; @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
|
|
|
|
CCS811_GetValue:
|
|
lds r17, ccs811Flags
|
|
andi r17, CCS811_FLAGS_VALIDDATA
|
|
breq CCS811_GetValue_noData
|
|
cpi r16, CCS811_VALUE_TVOC
|
|
breq CCS811_GetValue_retTvoc
|
|
cpi r16, CCS811_VALUE_CO2
|
|
breq CCS811_GetValue_retCo2
|
|
CCS811_GetValue_noData:
|
|
clc
|
|
ret
|
|
CCS811_GetValue_retTvoc:
|
|
lds r18, ccs811ResponseData+3 ; value
|
|
lds r19, ccs811ResponseData+2
|
|
ldi r20, 1
|
|
clr r21
|
|
rjmp CCS811_GetValue_secRet
|
|
CCS811_GetValue_retCo2:
|
|
lds r18, ccs811ResponseData+1 ; value
|
|
lds r19, ccs811ResponseData
|
|
ldi r20, 1
|
|
clr r21
|
|
CCS811_GetValue_secRet:
|
|
sec
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
ccs811WaitMs:
|
|
ccs811WaitMs_loop1:
|
|
ldi r17, 10
|
|
ccs811WaitMs_loop2:
|
|
rcall Utils_WaitFor100MicroSecs
|
|
dec r17
|
|
brne ccs811WaitMs_loop2
|
|
dec r16
|
|
brne ccs811WaitMs_loop1
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CCS811_END:
|
|
.equ MODULE_SIZE_CCS811 = CCS811_END-CCS811_BEGIN
|
|
|
|
|