added modules for SGP30/40.

This commit is contained in:
Martin Preuss
2025-05-14 23:18:26 +02:00
parent fee3606a61
commit faa46c7e38
15 changed files with 771 additions and 11 deletions

View File

@@ -53,6 +53,13 @@ AppReportSensors_Fini:
;
AppReportSensors_OnEverySecond:
in r15, SREG
push r15
cli
rcall AppReportSensors_OnEverySecond_noIrqs
out SREG, r15
ret
AppReportSensors_OnEverySecond_noIrqs:
lds r16, reportSensorTimer
inc r16
cpi r16, APP_REPORT_SENSORS_INTERVAL_SECS
@@ -60,6 +67,13 @@ AppReportSensors_OnEverySecond:
clr r16
AppReportSensors_OnEverySecond_store:
sts reportSensorTimer, r16
#ifdef MODULES_SGP30
; push r16
; rcall SGP30_Measure
; pop r16
#endif
#ifdef MODULES_SI7021
cpi r16, 1
breq AppReportSensors_OnEverySecond_measureValue1
@@ -70,11 +84,30 @@ AppReportSensors_OnEverySecond_store:
cpi r16, 49
breq AppReportSensors_OnEverySecond_sendValue2
#endif
#ifdef MODULES_SGP40
cpi r16, 27
breq AppReportSensors_OnEverySecond_measureValue4
cpi r16, 55
breq AppReportSensors_OnEverySecond_sendValue4
#endif
#ifdef MODULES_SGP30
cpi r16, 29
breq AppReportSensors_OnEverySecond_measureValue5
cpi r16, 57
breq AppReportSensors_OnEverySecond_sendValue5
cpi r16, 59
breq AppReportSensors_OnEverySecond_sendValue6
#endif
#ifdef MODULES_DS18B20
cpi r16, 9
breq AppReportSensors_OnEverySecond_sendValue3
#endif
ret
#ifdef MODULES_SI7021
AppReportSensors_OnEverySecond_measureValue1:
rjmp SI7021_MeasureTemp
@@ -85,10 +118,29 @@ AppReportSensors_OnEverySecond_sendValue1:
AppReportSensors_OnEverySecond_sendValue2:
rjmp SI7021_SendHumidity
#endif
#ifdef MODULES_DS18B20
AppReportSensors_OnEverySecond_sendValue3:
rjmp Ds18b20_SendTemperature
#endif
#ifdef MODULES_SGP40
AppReportSensors_OnEverySecond_measureValue4:
rjmp SGP40_MeasureRawSignal
AppReportSensors_OnEverySecond_sendValue4:
rjmp SGP40_SendTVOC
#endif
#ifdef MODULES_SGP30
AppReportSensors_OnEverySecond_measureValue5:
rjmp SGP30_Measure
AppReportSensors_OnEverySecond_sendValue5:
rjmp SGP30_SendTVOC
ret
AppReportSensors_OnEverySecond_sendValue6:
rjmp SGP30_SendCO2
#endif
; @end

View File

@@ -88,6 +88,20 @@
.include "common/multiply.asm"
#endif
#ifdef MODULES_SGP30
.include "modules/sgp30/main.asm"
#ifdef MODULES_NETWORK
.include "modules/sgp30/send.asm"
#endif
#endif
#ifdef MODULES_SGP40
.include "modules/sgp40/main.asm"
#ifdef MODULES_NETWORK
.include "modules/sgp40/send.asm"
#endif
#endif
#ifdef MODULES_OWI_MASTER
.include "modules/owimaster/main.asm"
#endif

View File

@@ -148,6 +148,7 @@ sysOnEveryMinute:
#ifdef APPS_STATS
rcall AppStats_OnEveryMinute
#endif
rjmp onEveryMinute
; @end

View File

@@ -87,6 +87,14 @@ initModules:
rcall SI7021_Init
#endif
#ifdef MODULES_SGP30
rcall SGP30_Init
#endif
#ifdef MODULES_SGP40
rcall SGP40_Init
#endif
#ifdef MODULES_DS18B20
rcall Ds18b20_Init
#endif

View File

@@ -103,6 +103,19 @@
; ---------------------------------------------------------------------------
; SGB 30
.equ SGP30_ADDR = 0x58
; ---------------------------------------------------------------------------
; SGB 40
.equ SGP40_ADDR = 0x59
; ---------------------------------------------------------------------------
; 1-Wire Master
;

View File

@@ -69,6 +69,8 @@
;#define MODULES_LCD
;#define LCD_MINIMAL_FONT
#define MODULES_SI7021
#define MODULES_SGP30
;#define MODULES_SGP40
;#define MODULES_STATS
;#define MODULES_OWI_MASTER
;#define MODULES_DS18B20

View File

@@ -19,6 +19,8 @@
motion
owimaster
reed
sgp30
sgp40
si7021
sk6812
stats

12
avr/modules/sgp30/0BUILD Normal file
View File

@@ -0,0 +1,12 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
send.asm
</extradist>
</gwbuild>

327
avr/modules/sgp30/main.asm Normal file
View File

@@ -0,0 +1,327 @@
; ***************************************************************************
; 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_Measure
;
; Expects interrupts being disabled!
;
; @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

View File

@@ -0,0 +1,43 @@
; ***************************************************************************
; 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. *
; ***************************************************************************
.cseg
; ---------------------------------------------------------------------------
; @routine SGP30_SendTVOC
SGP30_SendTVOC:
ldi r16, SGP30_VALUE_TVOC
rcall SGP30_GetValue
brcc SGP30_SendTVOC_end
ldi r17, VALUE_ID_TVOC ; VALUE ID
ldi r22, AQHOME_VALUETYPE_TVOC ; VALUE TYPE
rcall Main_SendValueReport
SGP30_SendTVOC_end:
ret
; @end
; ---------------------------------------------------------------------------
; @routine SGP30_SendCO2
SGP30_SendCO2:
ldi r16, SGP30_VALUE_CO2
rcall SGP30_GetValue
brcc SGP30_SendCO2_end
ldi r17, VALUE_ID_CO2 ; VALUE ID
ldi r22, AQHOME_VALUETYPE_CO2 ; VALUE TYPE
rcall Main_SendValueReport
SGP30_SendCO2_end:
ret
; @end

12
avr/modules/sgp40/0BUILD Normal file
View File

@@ -0,0 +1,12 @@
<?xml?>
<gwbuild>
<extradist>
main.asm
send.asm
</extradist>
</gwbuild>

212
avr/modules/sgp40/main.asm Normal file
View File

@@ -0,0 +1,212 @@
; ***************************************************************************
; 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

View File

@@ -0,0 +1,25 @@
; ***************************************************************************
; 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. *
; ***************************************************************************
.cseg
; ---------------------------------------------------------------------------
; @routine SGP40_SendTVOC
SGP40_SendTVOC:
rcall SGP40_GetValue
brcc SGP40_SendTVOC_end
ldi r17, VALUE_ID_TVOC ; VALUE ID
ldi r22, AQHOME_VALUETYPE_TVOC ; VALUE TYPE
rcall Main_SendValueReport
SGP40_SendTVOC_end:
ret
; @end

View File

@@ -168,18 +168,8 @@ SI7021_MeasureHumidity_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
rjmp twiCheckPresence

View File

@@ -107,6 +107,30 @@ TWI_Master_Run:
; ---------------------------------------------------------------------------
; @routine twiCheckPresence
;
; Expects interrupts being disabled!
;
; @param r16 address to check (with read bit set!)
; @return CFLAG set if okay, clear on error
; @clobbers (R16, R17, R18, R22)
twiCheckPresence:
rcall twiStart ; (R22)
rcall twiSendByte ; (R16, R17, R18, R22)
; rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc twiCheckPresence_notfound
rcall twiStop ; (R22)
sec
ret
twiCheckPresence_notfound:
rcall twiStop ; (R22)
clc
ret
; @end
; ---------------------------------------------------------------------------
; twiStart
@@ -257,6 +281,29 @@ twiWriteBit_clockReleased:
; ---------------------------------------------------------------------------
; @routine twiSendFromFlashExpectAck
;
; Write bytes from flash to TWI expecting ACK bits.
;
; @param Z pointer to data in FLASH to send (prepared for "LPM"!)
; @param r19 number of bytes to send
; @return CFLAG set if okay, cleared on error
; @clobbers R16, R17, R18, R22, Z
twiSendFromFlashExpectAck:
twiSendFromFlashExpectAck_loop:
lpm r16, Z+
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc twiSendFromFlashExpectAck_ret
dec r19
brne twiSendFromFlashExpectAck_loop
sec
twiSendFromFlashExpectAck_ret:
ret
; @end
; ---------------------------------------------------------------------------
; twiSendByte
;