view src/i2c.asm @ 656:8af5aefbcdaf default tip

Update to 3.31 beta
author heinrichsweikamp
date Thu, 27 Nov 2025 18:32:58 +0100
parents c7b7b8a358cd
children
line wrap: on
line source

;=============================================================================
;
;   File i2c.asm                            * combined next generation V3.09.4b
;
;   I2C Interface
;
;   Copyright (c) 2012, JD Gascuel, heinrichs weikamp gmbh, all right reserved.
;=============================================================================
;
;   Compass0
;   --------
;   HMC5883L's read address  (8-Bit):  0x3D
;   HMC5883L's write address (8-Bit):  0x3C
;   MMA8452Q's read address  (8-Bit):  0x39
;   MMA8452Q's write address (8-Bit):  0x38
;
;   Compass1
;   --------
;   LSM303D's read address  (8-Bit):   0x3D
;   LSM303D's write address (8-Bit):   0x3C
;
;   Compass2
;   --------
;   LSM303AGR's Compass read address       (8-Bit):  0x3D
;   LSM303AGR's Compass write address      (8-Bit):  0x3C
;   LSM303AGR's Acceleration read address  (8-Bit):  0x33
;   LSM303AGR's Acceleration write address (8-Bit):  0x32
;    
;   Compass3
;   --------
;   LSM303C's Compass read address          (8-Bit): 0x3D
;   LSM303C's Compass write address         (8-Bit): 0x3C
;   LSM303C's Acceleration read address	    (8-Bit): 0x3B
;   LSM303C's Acceleration write address    (8-Bit): 0x3A
;
;   RX Circuity
;   -----------
;   RX Circuity read address  (8-Bit):  0x51
;   RX Circuity write address (8-Bit):  0x50
;    
;   Battery gauge    
;   -------------
;   LTC2942 read address  (8-Bit): 0xC9   
;   LTC2942 write address (8-Bit): 0xC8 
;    
;   Alternative Battery gauge    
;   -------------
;   LTC2959 read address  (8-Bit): 0xC7   
;   LTC2959 write address (8-Bit): 0xC6 
;
;   Alternative pressure sensor
;   -----------
;   MS5837 read address  (8-Bit):  0xED
;   MS5837 write address (8-Bit):  0xEC
;
;

; HISTORY
;  2012-08-22 : [mH] Creation
;  2018-02-18 : [mH] Sync with hwOS Sport release


#include "hwos.inc"						; Mandatory header
#include "wait.inc"
#include "math.inc"
#include "eeprom_rs232.inc"
    

;=============================================================================
i2c		CODE
;=============================================================================



;-----------------------------------------------------------------------------
; Helper Function - get two Bytes and divide hi:lo/16 (signed)
;
I2C_TwoBytesRX_div16:
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; copy data byte to hi
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; copy data byte to lo
I2C_TwoBytesRX_div16_2:					; divide hi:lo/16 (signed) only
	bcf		STATUS,C
	btfsc	hi,7						; copy sign bit to carry
	bsf		STATUS,C
	rrcf	hi							; /2
	rrcf	lo
	;bra	I2C_TwoBytesRX_div8			; continue dividing hi:lo/8 (signed)


;-----------------------------------------------------------------------------
; Helper Function - divide hi:lo/8 (signed)
;
I2C_TwoBytesRX_div8:
	bcf		STATUS,C
	btfsc	hi,7						; copy sign bit to carry
	bsf		STATUS,C
	rrcf	hi							; /4
	rrcf	lo
	bcf		STATUS,C
	btfsc	hi,7						; copy sign bit to carry
	bsf		STATUS,C
	rrcf	hi							; /8
	rrcf	lo
	bcf		STATUS,C
	btfsc	hi,7						; copy sign bit to carry
	bsf		STATUS,C
	rrcf	hi							; /16
	rrcf	lo
	return								; done


;-----------------------------------------------------------------------------
; Read Accelerometer
;
	global	I2C_RX_accelerometer
I2C_RX_accelerometer:
	btfsc	compass_type3					; compass3 ?
	bra		I2C_RX_accelerometer_compass3	; YES
	btfsc	compass_type2					; compass2 ?
	bra		I2C_RX_accelerometer_compass2	; YES
	btfsc	compass_type1					; compass1 ?
	bra		I2C_RX_accelerometer_compass1	; YES
	;bra	I2C_RX_accelerometer_compass0	; NO  - compass0 then

;I2C_RX_accelerometer_compass0:
	rcall	I2C_SEN						; start condition
	movlw	0x38						; address
	rcall	I2C_TX						; send byte
	movlw	0x00						; ??
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x39						; address
	rcall	I2C_TX						; send byte
	rcall	I2C_OneByteRX				; get  status byte
	movf	SSP1BUF,W					; copy status byte to WREG

	; Non-flipped screen:
	; Chip orientation on the PCB requires
	; Original = corrected
	; x = -x
	; y = -y
	; z = -z

	; Flipped screen:
	; Chip orientation on the PCB requires
	; Original = corrected
	; x = x
	; y = y
	; z = -z

	rcall	I2C_TwoBytesRX_div16		; get two bytes and divide /16 (signed)
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_accelerometer2		; YES
	comf	hi							; NO  - 16 bit sign change
	negf	lo							;     - ....
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;     - YES - do it
I2C_RX_accelerometer2:
	MOVII	mpr,accel_DX				; copy result to accel_DX

	rcall	I2C_TwoBytesRX_div16		; get two bytes and divide /16 (signed)
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_accelerometer3		; YES
	comf	hi							; NO  - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
I2C_RX_accelerometer3:
	MOVII	mpr,accel_DY				; copy result to accel_DY

	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; copy data byte to hi
	rcall	I2C_OneByteRX_NACK			; receive last byte with not acknowledge
	movff	SSP1BUF,lo					; copy data byte to lo
	rcall	I2C_TwoBytesRX_div16_2		; divide hi:lo/16 (signed)
	comf	hi							; 16 bit sign change
	negf	lo							; ...
	btfsc	STATUS,C					; carry to propagate?
	incf	hi,F						; YES - do it
	MOVII	mpr,accel_DZ				; copy result to accel_DZ
	bra	I2C_PEN						; stop condition


I2C_RX_accelerometer_compass1:
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	b'10101000'					; 0x28 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x3D						; address

I2C_RX_accelerometer_common:			; common part for compass 1,2 and 3
	rcall	I2C_TX						; send byte

	; Non-flipped screen:
	; Chip orientation on the PCB requires
	; Original = Corrected
	; x = -x (Compass 1)
	; x = x (Compass 2)
	; y = -y
	; z = -z

	; Flipped screen:
	; Chip orientation on the PCB requires
	; Original = Corrected
	; x = x (Compass 1)
	; x = -x (Compass 2)
	; y = y
	; z = -z

	; Dump the accelerator data
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; accel_DX+0
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; accel_DX+1
	rcall	I2C_TwoBytesRX_div16_2		; divide lo:hi/16 (signed) only
	btfss	compass_type2				; compass 2?
	bra		I2C_RX_accelerometer1_c1	; NO  - compass 1
	; compass 2
	btfss	flip_screen					; 180° rotation?
	bra		I2C_RX_accelerometer2_c1	; NO  - continue with normal compass1 routines for Y and Z
	; flipped compass 2, negate x
	comf	hi							; YES - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
	bra		I2C_RX_accelerometer2_c1	;     - continue with normal compass1 routines for Y and Z

I2C_RX_accelerometer1_c1:
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_accelerometer2_c1	; YES
	; non-flipped compass 1, negate x
	comf	hi							; NO  - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
I2C_RX_accelerometer2_c1:
	; flipped compass 1, non-flipped compass 2
	MOVII	mpr,accel_DX				; copy result
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; copy accel_DY+0 to lo
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; copy accel_DY+1 to hi
	rcall	I2C_TwoBytesRX_div16_2		; divide hi:lo/16 (signed) only
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_accelerometer3_c1	; YES
	comf	hi							; NO  - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
I2C_RX_accelerometer3_c1:
	MOVII	mpr,accel_DY				; copy result
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; accel_DZ+0
	rcall	I2C_OneByteRX_NACK			; receive last byte with not acknowledge
	movff	SSP1BUF,hi					; accel_DZ+1
	rcall	I2C_PEN						; stop condition
	rcall	I2C_TwoBytesRX_div16_2		; divide lo:hi/16 (signed) only
	comf	hi							; 16 bit sign change for Z
	negf	lo							; ...
	btfsc	STATUS,C					; carry to propagate?
	incf	hi,F						; YES - do it
	MOVII	mpr,accel_DZ				; copy result
	return								; done


I2C_RX_accelerometer_compass2:
	rcall	I2C_SEN						; start condition
	movlw	0x32						; address
	rcall	I2C_TX						; send byte
	movlw	b'10101000'					; 0x28 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x33						; address
	bra		I2C_RX_accelerometer_common	; continue with common part

I2C_RX_accelerometer_compass3:
	rcall	I2C_SEN						; start condition
	movlw	0x3A						; address
	rcall	I2C_TX						; send byte
	movlw	0x28						; 0x28 (OUT_X_L_A)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x3B						; address
	bra		I2C_RX_accelerometer_common	; continue with common part



;-----------------------------------------------------------------------------
; Read Compass
;
 IFDEF _compass

	global	I2C_RX_compass
I2C_RX_compass:
	btfsc	compass_type3				; compass 3 ?
	bra		I2C_RX_compass3				; YES
	btfsc	compass_type2				; compass 2 ?
	bra		I2C_RX_compass2				; YES
	btfsc	compass_type1				; compass 1 ?
	bra		I2C_RX_compass1				; YES
	;bra	I2C_RX_compass0				; NO  - compass 0 then

;I2C_RX_compass0:
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address + write bit
	rcall	I2C_TX						; send byte
	movlw	0x03						; Point to Data Output X MSB Register (0x03)
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	rcall	I2C_SEN						; start condition
	movlw	0x3D						; address + read bit
	rcall	I2C_TX						; send byte

	; Compass IC sends data in following order:
	; x MSB
	; x LSB
	; z MSB
	; z LSB
	; y MSB
	; y LSB

	; Non-flipped screen
	; Chip orientation on the PCB requires
	; Original = Corrected
	; x = -y
	; z = z
	; y = x

	; Flipped screen
	; Chip orientation on the PCB requires
	; Original = Corrected
	; x = y
	; z = z
	; y = -x

	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,compass_DY+1		; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,compass_DY+0		; data byte
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_compass0_2			; NO
	banksel	compass_DY					; YES - flip Y
	comf	compass_DY+1				;     - 16 bit sign change
	negf	compass_DY+0
	btfsc	STATUS,C					;     - carry to propagate?
	incf	compass_DY+1,F				;       YES - do it
	banksel	common
I2C_RX_compass0_2:
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,compass_DZ+1		; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,compass_DZ+0		; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,compass_DX+1		; data byte
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,compass_DX+0		; data byte
	rcall	I2C_PEN						; stop condition
	btfss	flip_screen					; 180° rotation?
	return								; NO  - done
	banksel	compass_DX					; YES - flip X
	comf	compass_DX+1				;     - 16 bit sign change
	negf	compass_DX+0
	btfsc	STATUS,C					;     - carry to propagate?
	incf	compass_DX+1,F				;       YES - do it
	banksel	common						; back to bank common
	return								; done


I2C_RX_compass1:						; compass type 1
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	b'10001000'					; 0x08 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x3D						; address
	rcall	I2C_TX						; send byte
	;rcall	WaitMSSP					; TODO needed? (mH)
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; data byte
	rcall	I2C_TwoBytesRX_div8			; divide hi,lo by 8 (signed)
	MOVII	mpr,compass_DX				; copy result
	btfss	flip_screen					; 180° rotation?
	bra		I2C_RX_compass1_1			; NO
	banksel	compass_DX					; YES - flip X
	comf	compass_DX+1				;     - 16 bit sign change
	negf	compass_DX+0
	btfsc	STATUS,C					;     - carry to propagate?
	incf	compass_DX+1,F				;       YES - do it
	banksel	common
I2C_RX_compass1_1:
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; data byte
	rcall	I2C_TwoBytesRX_div8			; divide hi, lo by 8 (signed)
	MOVII	mpr,compass_DY
	btfss	flip_screen					; 180° rotation?
	bra		I2C_RX_compass1_2			; NO
	banksel	compass_DY					; YES - flip Y
	comf	compass_DY+1				;     - 16 bit sign change
	negf	compass_DY+0				;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	compass_DY+1,F				;       YES - do it
	banksel	common
I2C_RX_compass1_2:
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX_NACK			; receive last byte with not acknowledge
	movff	SSP1BUF,hi					; data byte
	rcall	I2C_TwoBytesRX_div8			; divide hi, lo by 8 (signed)
	MOVII	mpr,compass_DZ				; copy result
	bra	I2C_PEN						; stop condition



I2C_RX_compass2:						; compass type 2
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xE8						; 0x68 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x3D						; address
	rcall	I2C_TX						; send byte
I2C_RX_compass2_xx:						; compass 3 joins in here
;	rcall	WaitMSSP					; wait for TX to complete (not needed, as included in I2C_TX)
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; data byte
;	rcall	I2C_TwoBytesRX_div8			; divide hi, lo by 8 (signed)
	btfsc	flip_screen					; 180° rotation?
	bra		I2C_RX_compass2_1			; YES - do nothing with X
										; NO  - flip X
	comf	hi							;     - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
I2C_RX_compass2_1:
	MOVII	mpr,compass_DX
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,hi					; data byte
;	rcall	I2C_TwoBytesRX_div8			; divide hi, lo by 8 (signed)
	btfss	flip_screen					; 180° rotation?
	bra		I2C_RX_compass2_2			; NO  - do nothing with Y
										; YES - flip Y
	comf	hi							;     - 16 bit sign change
	negf	lo							;     - ...
	btfsc	STATUS,C					;     - carry to propagate?
	incf	hi,F						;       YES - do it
I2C_RX_compass2_2:
	MOVII	mpr,compass_DY
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movff	SSP1BUF,lo					; data byte
	rcall	I2C_OneByteRX_NACK			; receive last byte with not acknowledge
	movff	SSP1BUF,hi					; data byte
;	rcall	I2C_TwoBytesRX_div8			; divide hi, lo by 8 (signed)
	MOVII	mpr,compass_DZ				; copy result
	bra	I2C_PEN						; stop condition



I2C_RX_compass3:						; compass type 3
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xA8						; 0x28 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0x3D						; address
	rcall	I2C_TX						; send byte
	bra		I2C_RX_compass2_xx			; join with compass 2 code

 ENDIF	; _compass


;-----------------------------------------------------------------------------
; Initialize Compass / Accelerometer Chip
;
	global	I2C_init_compass
I2C_init_compass:
	bsf		compass_present				; Set global compass flag
	bsf		compass_enabled				; flag compass will be enabled
	bcf		compass_type2				; clear in preparation of chip detection
	bcf		compass_type3				; ...

	; probe for compass 3
	rcall	I2C_SEN						; start condition
	movlw	0x3A						; address byte + write bit
	movwf	SSP1BUF						; control byte
	rcall	WaitMSSP					; wait for TX to complete
	; we need the ACKSTAT bit! Do not use I2C_TX routine here which might reset this bit!
	btfss	SSP1CON2,ACKSTAT			; ACK received?
	bsf		compass_type3				; YES - ACK was send, compass 3 found
	rcall	I2C_PEN						; stop condition

	btfsc	compass_type3				; compass 3 found?
	bra		I2C_init_compass3			; YES - initialize compass 3

	; probe for compass 2
	rcall	I2C_SEN						; start condition
	movlw	0x32						; address byte + write bit
	movwf	SSP1BUF						; control byte
	rcall	WaitMSSP					; wait for TX to complete
	; we need the ACKSTAT bit! Do not use I2C_TX routine here which might reset this bit!
        btfss	SSP1CON2,ACKSTAT			; ACK received?
	bsf		compass_type2				; YES - ACK send, compass 2 found
	rcall	I2C_PEN						; stop condition

	btfsc	compass_type2				; compass 2 found?
	bra		I2C_init_compass2			; YES - initialize compass 2

	; probe for compass 1
	bsf		compass_type1				; assume compass 1 by default
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x0F						; ??
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	rcall	I2C_SEN						; start condition
	movlw	0x3D						; address
	rcall	I2C_TX						; send byte
	rcall	I2C_OneByteRX				; receive 1 byte with acknowledge
	movlw	0x49						; 0x49 = compass 1
	cpfseq	SSP1BUF						; 0x49 received?
	bcf		compass_type1				; NO - clear flag for compass 1
	rcall	I2C_PEN						; stop condition

	btfsc	compass_type1				; compass 1 found?
	bra		I2C_init_compass1			; YES - initialize compass 1
	
	; probe for compass 0
	bsf	compass_type0					; assume compass 0 by default
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address + write bit
	rcall	I2C_TX						; send byte
	movlw	0x0A						; Point to Identification Register A
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	rcall	I2C_SEN						; start condition
	movlw	0x3D						; address + read bit
	rcall	I2C_TX						; send byte
	rcall	I2C_OneByteRX					; receive 1 byte with acknowledge
	movlw	b'01001000'					; Identification Register A must be "H"
	cpfseq	SSP1BUF						; Compare with received value
	bcf	compass_type0					; Not equal -> Not compass 0
	rcall	I2C_PEN						; stop condition
	
	btfsc	compass_type0				; compass 0 found?
	bra	I2C_init_compass0			; YES - initialize compass 0
;	; no compass of any type found
	bcf	compass_present				; Delete global compass flag
	return


I2C_init_compass0:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x00						; ??
	rcall	I2C_TX						; send byte
	movlw	b'01101000'					; ConfigA: 3 Hz, 8 samples averaged
	rcall	I2C_TX						; send byte
	movff	opt_compass_gain,i2c_temp1	; 0-7 (230 LSB/Gauss to 1370 LSB/Gauss)
	swapf	i2c_temp1,F					;
	comf	i2c_temp1,F					;
	bcf		STATUS,C					;
	rlcf	i2c_temp1					;
	movf	i2c_temp1,W					;
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; select continuous mode
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	; accelerometer
	rcall	I2C_sleep_accelerometer0	; registers can only be changed in standby mode

	rcall	I2C_SEN						; start condition
	movlw	0x38						; address
	rcall	I2C_TX						; send byte
	movlw	0x0E						; XYZ_DATA_CFG
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; high pass filter = 0, +/- 2 g range
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	rcall	I2C_SEN						; start condition
	movlw	0x38						; address
	rcall	I2C_TX						; send byte
	movlw	0x2A						; CTRL_REG1
	rcall	I2C_TX						; send byte
;	movlw	b'00110000'					; CTRL_REG1: 160 ms data rate, standby mode
	movlw	b'00110100'					; CTRL_REG1: 160 ms data rate, standby mode, reduced noise mode
	rcall	I2C_TX						; send byte
	movlw	b'00000010'					; CTRL_REG2: high-res in active mode
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	rcall	I2C_SEN						; start condition
	movlw	0x38						; address
	rcall	I2C_TX						; send byte
	movlw	0x2A						; CTRL_REG1
	rcall	I2C_TX						; send byte
;	movlw	b'00110001'					; CTRL_REG1: 160 ms data rate, active  mode
	movlw	b'00110101'					; CTRL_REG1: 160 ms data rate, standby mode, reduced noise mode, active Mode
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition



I2C_init_compass1:
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x9F						; 1F with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL0
	rcall	I2C_TX						; send byte
	movlw	b'00101111'					; CTRL1 (6.25 Hz, BDU=0, x,y,z = ON)
	rcall	I2C_TX						; send byte
	movlw	b'11000000'					; CTRL2 (50 Hz, +/- 2g)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL3
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL4
	rcall	I2C_TX						; send byte
	movlw	b'01100100'					; CTRL5 HIGH res, 6.25 Hz
	rcall	I2C_TX						; send byte
	movff	opt_compass_gain,i2c_temp1	; 0-7 (230 LSB/Gauss to 1370 LSB/Gauss)
	movlw	b'01100000'					; CTRL6 Full scale (+/-12 Gauss -> 2730 LSB/Gauss)
	dcfsnz	i2c_temp1,F					; = 1?
	movlw	b'01100000'					; YES - CTRL6 Full scale (+/-12 Gauss -> 2730 LSB/Gauss)
	dcfsnz	i2c_temp1,F					; = 2?
	movlw	b'01000000'					; YES - CTRL6 (+/-8 Gauss)
	dcfsnz	i2c_temp1,F					; = 3?
	movlw	b'01000000'					; YES - CTRL6 (+/-8 Gauss)
	dcfsnz	i2c_temp1,F					; = 4?
	movlw	b'00100000'					; YES - CTRL6 (+/-4 Gauss)
	dcfsnz	i2c_temp1,F					; = 5?
	movlw	b'00100000'					; YES - CTRL6 (+/-4 Gauss)
	dcfsnz	i2c_temp1,F					; = 6?
	movlw	b'00000000'					; YES - CTRL6 (+/-2 Gauss)
	dcfsnz	i2c_temp1,F					; = 7?
	movlw	b'00000000'					; YES - CTRL6 (+/-2 Gauss)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL7 Continuous Mode
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition

	; accelerometer initializes along with magnetic sensor


I2C_init_compass2:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xE0						; 0x60 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'10000000'					; CFG_REG_A_M (10Hz, Continuous) 0x60 0x00
	rcall	I2C_TX						; send byte
	movlw	b'00000011'					; CFG_REG_B_M (low-pass filter enabled) 0x61 (set pulse is released every 63 ODR)
	rcall	I2C_TX						; send byte
	movlw	b'00010000'					; CFG_REG_C_M BDU=1 0x62 0x57
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	; accelerometer
	rcall	I2C_SEN						; start condition
	movlw	0x32						; address
	rcall	I2C_TX						; send byte
	movlw	0x9F						; 1F with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; TEMP_CFG_REG_A (Temp sensor off)
	rcall	I2C_TX						; send byte
	movlw	b'00100111'					; CTRL_REG1_A (10Hz, x,y,z = ON)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG2_A
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG3_A
	rcall	I2C_TX						; send byte
	movlw	b'00001000'					; CTRL_REG4_A (BDU=0, +/-2g, HR=1)
	rcall	I2C_TX						; send byte
;	movlw	b'00000000'					; CTRL_REG5_A
;	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition


I2C_init_compass3:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xA0						; 0x20 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'01110000'					; CTRL_REG1_M (10Hz, X and Y in Ultra-high performance mode) 0x20
	rcall	I2C_TX						; send byte
	movlw	b'01100000'					; CTRL_REG2_M (Full-scale: +/- 16gauss) 0x21
	rcall	I2C_TX						; send byte
	movlw	b'01000000'					; CTRL_REG3_M (Continuous) 0x22
	rcall	I2C_TX						; send byte
	movlw	b'00001100'					; CTRL_REG4_M (Z in Ultra-high performance mode) 0x23
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG5_M 0x24
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG5_M 0x24
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	;accelerometer
	rcall	I2C_SEN						; start condition
	movlw	0x3A						; address
	rcall	I2C_TX						; send byte
	movlw	0x20
	rcall	I2C_TX						; send byte
	movlw	b'10010111'					; CTRL_REG1_A (100Hz, x,y,z = ON, BDU=OFF) 0x20
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG2_A 0x21
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG3_A 0x22
	rcall	I2C_TX						; send byte
	movlw	b'11001100'					; CTRL_REG4_A 0x23
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition
	

	
;-----------------------------------------------------------------------------
; Deactivate Compass / Accelerometer
;
	global	I2C_sleep_compass
I2C_sleep_compass:
	btfss	compass_enabled				; compass active?
	return								; NO - done
	bcf		compass_enabled
	btfsc	compass_type3				; compass 3 ?
	bra		I2C_sleep_compass3			; YES
	btfsc	compass_type2				; compass 2 ?
	bra		I2C_sleep_compass2			; YES
	btfsc	compass_type1				; compass 1 ?
	bra		I2C_sleep_compass1			; YES
	;bra	I2C_sleep_compass0			; NO  - must be compass 0 then


I2C_sleep_compass0:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x00						; ??
	rcall	I2C_TX						; send byte
	movlw	b'01101000'					; ConfigA
	rcall	I2C_TX						; send byte
	movlw	b'00100000'					; ConfigB
	rcall	I2C_TX						; send byte
	movlw	b'00000010'					; idle mode
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

I2C_sleep_accelerometer0:
	; accelerometer
	rcall	I2C_SEN						; start condition
	movlw	0x38						; address
	rcall	I2C_TX						; send byte
	movlw	0x2A						; CTRL_REG1
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; standby mode
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition


I2C_sleep_compass1:
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x20						; CTRL_REG1
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; data for CTRL_REG1: acceleration sensor power-down mode
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0x26						; CTRL_REG7
	rcall	I2C_TX						; send byte
	movlw	b'00000010'					; data for CTRL_REG7: magnetic sensor power-down mode
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition

	; accelerometer sleeps with magnetic sensor


I2C_sleep_compass2:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xE0						; 0x60 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'00000011'					; CFG_REG_A_M    0x60 (idle mode))
	rcall	I2C_TX						; send byte
	movlw	b'00000100'					; CFG_REG_B_M    0x61 (set pulse is released only at power-on after PD condition)
	rcall	I2C_TX						; send byte
	movlw	b'01010001'					; CFG_REG_C_M    0x62
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; INT_CTRL_REG_M 0x63
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	; accelerometer
	rcall	I2C_SEN						; start condition
	movlw	0x32						; address
	rcall	I2C_TX						; send byte
	movlw	0x9F						; 1F with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; TEMP_CFG_REG_A  0x1F (temp sensor off)
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG1_A     0x20 (all off)
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition


I2C_sleep_compass3:
	; magnetic
	rcall	I2C_SEN						; start condition
	movlw	0x3C						; address
	rcall	I2C_TX						; send byte
	movlw	0xA2						; 0x22 with auto-increment (MSB=1)
	rcall	I2C_TX						; send byte
	movlw	b'01000010'					; CTRL_REG3_M (power-down) 0x22
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	; accelerometer
	rcall	I2C_SEN						; start condition
	movlw	0x3A						; address
	rcall	I2C_TX						; send byte
	movlw	0x20
	rcall	I2C_TX						; send byte
	movlw	b'00000000'					; CTRL_REG1_A (100Hz, x,y,z = OFF) 0x20
	rcall	I2C_TX						; send byte
	bra	I2C_PEN						; stop condition
	
	
;-----------------------------------------------------------------------------
; Helper Function - receive 1 Byte with Not-Acknowledge
;
I2C_OneByteRX_NACK:
	rcall	I2C_RCEN					; enable receive mode
	bsf	SSP1CON2,ACKDT					; set ACKDT flag
	rcall	I2C_ACKEN					; send master acknowledge
	bcf	SSP1CON2,ACKDT					; reset ACKDT flag
	return


;-----------------------------------------------------------------------------
; Helper Function - receive 1 Byte with Acknowledge
;
I2C_OneByteRX:
	rcall	I2C_RCEN					; enable receive mode
	bra	I2C_ACKEN					; send master acknowledge
	
;-----------------------------------------------------------------------------
; Helper Function - send 1 Byte, wait for end of transmission and check ackn
; add WREG to checksum byte first
I2C_TX_CHKSUM:
	addwf	sub_a+0,F					; add to checksum
;	bra	I2C_TX
;-----------------------------------------------------------------------------
; Helper Function - send 1 Byte, wait for end of transmission and check ackn
;
I2C_TX:
	movwf	SSP1BUF						; put byte to be sent into TX buffer
	btfss	i2c_error_flag_lock				; vault in use already?
	movff	WREG,i2c_error_vault+0				; NO, Store address	
	rcall	WaitMSSP					; wait for TX to complete
	bra		I2C_Check_ACK				; check for acknowledge by receiver and return

	
;-----------------------------------------------------------------------------
; Helper Function - I2C Start Condition
;
I2C_SEN:
	bsf	SSP1CON2,SEN					; start condition
	bra	WaitMSSP					; wait for TX to complete (And return)

;-----------------------------------------------------------------------------
; Helper Function - I2C Repeated Start Condition
;
I2C_RSEN:
	bsf	SSP1CON2,RSEN					; repeated start condition
	bra	WaitMSSP					; wait for TX to complete (And return)
	

;-----------------------------------------------------------------------------
; Helper Function - I2C Stop Condition
;
I2C_PEN:
	bsf	SSP1CON2,PEN					; stop condition
	rcall	WaitMSSP					; wait for TX to complete (And return)
I2C_WAIT_100US:	
	; add ~100µs bus free time (min. 66µs recommended for LTC2959)
	; Remark: not exact: 122µs +/- 30.5 µs + worst case ISR latency
	setf	TMR5H						; initialize timer 5, high byte first
	movlw	.255-.4						; 4 x 31.5 µs = 126µs, min: 94,5µs
	movwf	TMR5L						; initialize timer 5, low  byte thereafter
	bcf	PIR5,TMR5IF					; clear timer 5 overrun flag
I2C_PEN_Loop:
	btfss	PIR5,TMR5IF					; did timer 5 overrun?
	bra	I2C_PEN_Loop					; NO  - repeat inner loop
	return

;-----------------------------------------------------------------------------
; Helper Function - Master Acknowledge	
;
I2C_ACKEN:
	bsf	SSP1CON2,ACKEN					; master acknowledge	
	bra	WaitMSSP					; wait for TX to complete (And return)

;-----------------------------------------------------------------------------
; Helper Function - Enable reeive mode
;
I2C_RCEN:
    	bsf	SSP1CON2,RCEN					; enable receive mode
	bra	WaitMSSP					; wait for TX to complete (And return)
	
;-----------------------------------------------------------------------------
; Helper Function - wait for TX to complete
;
WaitMSSP:
        btfss	i2c_error_flag_lock				; vault in use already?
	movff	SSP1BUF,i2c_error_vault+1			; NO, store value
	btfss	i2c_error_flag_lock				; vault in use already?
	movff	SSP1CON2,i2c_error_vault+2			; NO, store value
	clrf	i2c_temp1					; wait for max 256 loops
WaitMSSP_loop:
	decfsz	i2c_temp1,F					; decrement loop counter, timeout?
	bra		WaitMSSP2					; NO
	bra		I2CFail						; YES
WaitMSSP2:
	btfss	PIR1,SSP1IF					; TX completed?
	bra		WaitMSSP_loop				; NO  - loop
	bcf		PIR1,SSP1IF					; YES - clear TX completion flag
	return								;     - done


;-----------------------------------------------------------------------------
; Helper Function - Master NOT acknowledge and Stop
;
I2C_MasterNotAckStop:
	bsf		SSP1CON2,ACKDT				; set ACKDT flag
	rcall	I2C_ACKEN					; send master NOT acknowledge
	bcf		SSP1CON2,ACKDT				; reset ACKDT flag

	bra	I2C_PEN						; stop condition
	
;-----------------------------------------------------------------------------
; Helper Function - check for Acknowledge by Receiver
;
I2C_Check_ACK:
	btfss	SSP1CON2,ACKSTAT			; ACK received from slave?
	return								; YES - done
	;bra	I2CFail						; NO  - do some clean up


;-----------------------------------------------------------------------------
; Helper Function - clean up I2C Interface after missing Acknowledge
;
I2CFail:
	bsf		active_reset_ostc_rx		; reset RX circuitry (which may be the cause for the hang up)
	rcall	I2CReset					; reset I2C
	bcf		PIR1,SSP1IF					; clear TX completion flag
	bsf		i2c_error_flag				; set error flag
	bsf		i2c_error_flag_lock			; lock the error vault
	bcf		active_reset_ostc_rx		; release reset from RX circuitry
;	bcf	i2c_busy_temperature
;	bcf	i2c_busy_pressure
	return								; done


;-----------------------------------------------------------------------------
; Helper Function - Reset I2C Module
;
; recover in case something went wrong, i.g. slave holds SDA low
;
	global	I2CReset
I2CReset:
	clrf	SSP1CON1					; reset entire module
	clrf	SSP1CON2					; ...
	clrf	SSP1STAT					; ...
	bcf		TRISC,3						; SCL as OUTPUT
	bsf		TRISC,4						; SDA as input
	bcf		PORTC,3						; SCL = 0
	movlw	d'9'						; clock-out 9 clock cycles manually
	movwf	i2c_temp1					; ...
I2CReset_1:
	bsf		PORTC,3						; SCL = 1
	nop									; pause for 4 CPU cycles
	nop									; ...
	nop									; ...
	nop									; ...
	btfsc	PORTC,4						; SDA = 1 ?
	bra		I2CReset_2					; YES - SDA has been released from slave
	bcf		PORTC,3						; NO  - set SCL = 0
	nop									;     - pause for 2 CPU cycles
	nop									;     - ...
	bcf		PORTC,3						;     - SCL = 0
	nop									;     - pause for 2 CPU cycles
	nop									;     - ...
	decfsz	i2c_temp1,F					;     - clock counter, all cycles done?
	bra		I2CReset_1					;       NO - loop
I2CReset_2:
	bsf		TRISC,3						; SCL as input
	clrf	SSP1CON1					; setup I2C mode
	rcall	I2C_WAIT_100US					; ISR-Safe 100µs wait
	movlw	b'00000000'					; enable slew rate control
	movwf	SSP1STAT					; ...
	movlw	b'00101000'					; configure I2C module
	movwf	SSP1CON1					; ...
	movlw	b'00000000'					; ...
	movwf	SSP1CON2					; ...
	movlw	i2c_speed_value
	movwf	SSP1ADD						; ...
	rcall	I2C_WAIT_100US					; ISR-Safe 100µs wait
	movlw	.1
	addwf	i2c_error_counter+0
	movlw	.0
	addwfc	i2c_error_counter+1				; +1 on the error counter
	btfss	press_sensor_type				; =1: pressure sensor MS5837, =0: Pressure sensor MS5541
	return							; MS5541, Done.
	; reset the sensor
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x1E
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	WAITMS	.5						; 2.8ms according to datasheet
	return							; done


;-----------------------------------------------------------------------------
; Helper Function - Initialize Gauge IC again after an UVLO Event
;
battery_gauge_init_again:
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	return
	rcall   I2CReset
	movlw	0x02									; point to accumulated charge registers
	rcall	I2C_TX_GAUGE							; send byte to the LT2942 gauge IC
	movff	battery_accumulated_charge+1,SSP1BUF	; data byte
	rcall	WaitMSSP								; wait for TX to complete
	rcall	I2C_Check_ACK							; check for acknowledge by receiver
	movff	battery_accumulated_charge+0,SSP1BUF	; data byte
	rcall	WaitMSSP								; wait for TX to complete
	rcall	I2C_Check_ACK							; check for acknowledge by receiver
	rcall	I2C_PEN						; stop condition
	MOVII	battery_accumulated_charge,sub_a		; copy result to sub_a
	;bra	battery_gauge_init								; and initialize again...


;-----------------------------------------------------------------------------
; Initialize Gauge IC
;
	global	battery_gauge_init
battery_gauge_init:
	movlw	0x01						; point to control reg B / ADC Control
	rcall	I2C_TX_GAUGE					; send byte to the gauge IC
	movlw	b'11111000'					; automatic conversion every two seconds (LT2942)
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	movlw	b'00111000'					; ADC Mode to "Smart Sleep" (converts V, I, T every 52 seconds (tolerance < ±5%)) (LTC2959)
	rcall	I2C_TX						; send byte
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	movlw	b'01010000'					; 20µV deadband
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	rcall	I2C_TX						; send one byte more for the LTC2959
	bra	I2C_PEN						; stop condition

;-----------------------------------------------------------------------------
; Read Gauge IC - Status Register
;
	global	lt2942_get_status
lt2942_get_status:
	bcf	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	bcf	battery_gauge_available				; clear flag on default

	; try LTC2942
	rcall	I2C_SEN						; start condition
	movlw	0xC8						; address byte + Write bit
	movwf	SSP1BUF						; put byte to be sent into TX buffer
	rcall	WaitMSSP					; wait for TX to complete
	; we need the ACKSTAT bit! Do not use I2C_TX routine here which might reset this bit!
	btfss	SSP1CON2,ACKSTAT				; ACK received from slave?
	bsf	battery_gauge_available				; YES - set flag
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	btfsc	battery_gauge_available				; found?
	return							; YES - done
	
	; try LTC2959
	rcall	I2C_SEN						; start condition
	movlw	0xC6						; address byte + Write bit
	movwf	SSP1BUF						; put byte to be sent into TX buffer
	rcall	WaitMSSP					; wait for TX to complete
	; we need the ACKSTAT bit! Do not use I2C_TX routine here which might reset this bit!
	btfss	SSP1CON2,ACKSTAT				; ACK received from slave?
	bsf	battery_gauge_available				; YES - set flag
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	btfsc	battery_gauge_available				; found?
	bsf	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	return							; NO, return

;-----------------------------------------------------------------------------
; Read Gauge IC - Voltage
;
	global	lt2942_get_voltage
lt2942_get_voltage:
  
	btfsc	battery_gauge_type			; =1: Gauge IC LTC2959, =0: LT2942
	bra	LTC2959_get_voltage			; use new IC
	
	movlw	0x08						; point to voltage registers
	rcall	I2C_TX_GAUGE				; send    byte to   the LT2942 gauge IC
	rcall	I2C_RX_GAUGE				; receive byte from the LT2942 Gauge IC
	rcall	I2C_ACKEN					; send master acknowledge
	movff	SSP1BUF,xA+1				; copy received byte to xA+1
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xA+0				; copy received byte to xA+0
	
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	
	; convert voltage from raw value to Volt
	MOVLI	.6000,xB					; load conversion multiplicand into xB
	call	mult16x16					; xC = xA * xB -> multiply raw value in xA with conversion multiplicand
										; divide by 65536 instead of 65535, introducing an error of 65536/65535 = 0.002 %
	movff	xC+2,xC+0			; divide by 65536 can easily be done by just taking the 3rd and 4th byte of the multiplication result
	movff	xC+3,xC+1			; use xC+0 and xC+1 as temp

	movlw	.4					; battery voltage < 4*256mV (1.024)?
	cpfslt	xC+1					; < 1024 mV ?
	bra	lt2942_get_voltage_check_high		; NO  - Continue checking
	bra	battery_gauge_init_again			; YES - initialize gauge and return (and leave batt_voltage:2 untouched)
	
lt2942_get_voltage_check_high:
    	movlw	.17					; battery voltage >= 17*256mV (4.352V)?
	cpfslt	xC+1					;     - ... ?
	bra	battery_gauge_init_again			; YES - initialize gauge and return (and leave batt_voltage:2 untouched)
	; NO  - done
	movff	xC+0, batt_voltage+0
	movff	xC+1, batt_voltage+1
	bra	lt2942_get_accumulated_charge	;     - read coulomb counter (And return)
	
LTC2959_get_voltage:
	movlw	0x0F						; point to voltage registers
	rcall	I2C_TX_GAUGE				; send    byte to   the gauge IC
	rcall	I2C_RX_GAUGE				; receive byte from the Gauge IC
	rcall	I2C_ACKEN					; send master acknowledge
	movff	SSP1BUF,xA+1				; copy received byte to xA+1
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xA+0				; copy received byte to xA+0
	
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	
	; convert voltage from raw value to mV
	MOVLI	.62600,xB					; load conversion multiplicand into xB
	call	mult16x16					; xC = xA * xB -> multiply raw value in xA with conversion multiplicand
										; divide by 65536 instead of 65535, introducing an error of 65536/65535 = 0.002 %
	;movff	xC+2,xC+0			; divide by 65536 can easily be done by just taking the 3rd and 4th byte of the multiplication result
	;movff	xC+3,xC+1			; use xC+0 and xC+1 as temp

	movff	xC+2, batt_voltage+0
	movff	xC+3, batt_voltage+1
	rcall	lt2942_get_accumulated_charge	;     - read coulomb counter (And return)

	return								; done


;-----------------------------------------------------------------------------
; Read Gauge IC - Temperature
;
	global	lt2942_get_temperature
lt2942_get_temperature:					; read battery temperature
    	btfsc	battery_gauge_type			; =1: Gauge IC LTC2959, =0: LT2942
	bra	LTC2959_get_temperature

	movlw	0x0C						; point to temperature register
	rcall	I2C_TX_GAUGE				; send    byte to   the LT2942 gauge IC
	rcall	I2C_RX_GAUGE				; receive byte from the LT2942 Gauge IC
	rcall	I2C_ACKEN					; send master acknowledge
	movff	SSP1BUF,xA+1				; store raw temperature, high byte
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xA+0				; store raw temperature, low byte
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop

	; convert temperature from raw value to Kelvin in 0.1K
	MOVLI	.6000,xB					; load conversion multiplicand into xB
	call	mult16x16					; xC = xA * xB -> multiply raw value in xA with conversion multiplicand
										; divide by 65536 instead of 65535, introducing an error of 65536/65535 = 0.002 %
	movff	xC+2,battery_temperature+0	; divide by 65536 can easily be done by just taking the 3rd and 4th byte of the multiplication result
	movff	xC+3,battery_temperature+1	; ...

lt2942_get_temperature_common:	
	; check if battery is being charged right now
	btfss	cc_active					; in CC charging mode?
	return								; NO  - not charging, done

	; ignore false readings (>125°C)
	movlw	LOW	.3307
	movwf	sub_a+0
	movlw	HIGH	.3307
	movwf	sub_a+1
	MOVII	battery_temperature,    sub_b
	call	cmpU16						; sub_a - sub_b (with UNSIGNED values)
	btfsc	neg_flag					; result negative?
	return							; YES  - temperature > 125°C, not possible here. Skip test.
	
	; check for over-temperature while charging
	MOVLI	max_battery_charge_temp,sub_a
	MOVII	battery_temperature,    sub_b
	call	cmpU16						; sub_a - sub_b (with UNSIGNED values)
	btfss	neg_flag					; result negative?
	return								; NO  - temperature <= threshold, ok, done
	return
										; YES - too hot, disable charging circuitry
	bsf		charge_disable				;     - set      charging-inhibit signal
	bcf		charge_enable				;     - activate charging-inhibit signal
	bsf		battery_overtemp			;     - flag that the battery charging over-temperature protection has tripped
	return							;     - done

LTC2959_get_temperature:	
	return
    

;-----------------------------------------------------------------------------
; Read Gauge IC - Read State of Charge
;
lt2942_get_accumulated_charge:			; read accumulated charge and compute percent
    	btfsc	battery_gauge_type			; =1: Gauge IC LTC2959, =0: LTC2942
	bra	LTC2959_get_accumulated_charge
    
	; old LTC2942
	movlw	0x00						; point to status register
	rcall	I2C_TX_GAUGE				; send    byte to   the LT2942 gauge IC
	rcall	I2C_RX_GAUGE				; receive byte from the LT2942 Gauge IC
	rcall	I2C_ACKEN					; send master acknowledge
	movff	SSP1BUF,gauge_status_byte	; copy received byte to gauge_status_byte

	rcall	I2C_RCEN					; enable receive mode
	movf	SSP1BUF,W					; dump to WREG (Control)
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,sub_a+1				; copy received byte to sub_a+1
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,sub_a+0				; copy received byte to sub_a+0
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop

lt2942_get_accumulated_charge2:	
	btfsc	gauge_status_byte,0			; UVLO event ?
	rcall	battery_gauge_init_again			; YES - do an re-initialization
	MOVII	sub_a,battery_accumulated_charge	; save raw value
	; Compute batt_percent = (charge - battery_offset) / capacity_xxxxxx
	MOVII	battery_offset,sub_b		; get battery offset
	call	subU16						; sub_c = sub_a - sub_b (with signed values)
	clrf	batt_percent				; default batt_percent to zero
	btfsc	neg_flag					; result negative?
	bra		lt2942_set_to_zero_percent	; YES - keep LT2942 at zero percent and return

	; > zero, set batt_percent properly
	MOVII	sub_c,xA					; copy net charge to xA
	MOVII	battery_capacity,xB			; get battery capacity into xB
	call	div16x16					; xC = xA / xB with xA as remainder
	movff	xC+0,batt_percent			; result is battery percentage
	movlw	.100						; max. value is  100 %
	cpfslt	batt_percent				; batt_percent < 100 % ?
	movwf	batt_percent				; NO  - limit to 100 %
	movlw	battery_cycle_counter_unlock
	cpfsgt	batt_percent				; < threshold ?
	bcf	lock_cycle_counter			; Yes, unlock cycle counter
	return								; done

LTC2959_get_accumulated_charge:
	movlw	0x00						; point to status register
	rcall	I2C_TX_GAUGE				; send    byte to   the LT2942 gauge IC
	rcall	I2C_RX_GAUGE				; receive byte from the LT2942 Gauge IC
	rcall	I2C_ACKEN					; send master acknowledge
	movff	SSP1BUF,gauge_status_byte	; copy received byte to gauge_status_byte

	rcall	I2C_RCEN					; enable receive mode
	movf	SSP1BUF,W					; dump to WREG (ADC Control)
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movf	SSP1BUF,W					; dump to WREG (Coulumb Counter Control)
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xC+3				; copy received byte to xC+3
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xC+2				; copy received byte to xC+2
	rcall	I2C_ACKEN					; send master acknowledge
	
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xC+1				; copy received byte to xC+1
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,xC+0				; copy received byte to xC+0
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop

	MOVLI	.159,xB					; 159,4745717 (0,085mAh/533nAh)
	call	div32x16				; xC:4 = xC:4 / xB:2 with xA as remainder

	; clamp to 100% here
	tstfsz	xC+2					; Devision result > 0xFFFF
	setf	xC+0					; Yes, make sure xC:2 is 0xFFFF
	tstfsz	xC+2					; Devision result > 0xFFFF
	setf	xC+1					; Yes, make sure xC:2 is 0xFFFF
	
	movff	xC+1,sub_a+1
	movff	xC+0,sub_a+0				; put result in sub_a:2
;	
;	movff	sub_a+1,gp_debug+1
;	movff	sub_a+0,gp_debug+0
;	
	bra	lt2942_get_accumulated_charge2		; continue as with LT2942
	
	
lt2942_set_to_zero_percent:
    	btfsc	battery_gauge_type			; =1: Gauge IC LTC2959, =0: LT2942
	bra	LTC2959_set_to_zero_percent
    
	movlw	0x02						; point to accumulated charge registers
	rcall	I2C_TX_GAUGE				; send byte to the LT2942 gauge IC
	movff	battery_offset+1,SSP1BUF	; send battery offset, high byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movff	battery_offset+0,SSP1BUF	; send battery offset, low  byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	bra	I2C_PEN						; stop condition (and return)

LTC2959_set_to_zero_percent:
	; multiply battery_offset:2 with 159 and write result to LTC2959
	
	MOVII	battery_offset,xA
	MOVLI	.159,xB					; 159,4745717 (0,085mAh/533nAh)
	call	mult16x16				; xC:4 = xA:2 * xB:2
	
	movlw	0x03						; point to accumulated charge registers
	rcall	I2C_TX_GAUGE				; send byte to the LT2942 gauge IC
	movff	xC+3,SSP1BUF				; send battery offset
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movff	xC+2,SSP1BUF				; send battery offset
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movff	xC+1,SSP1BUF				; send battery offset
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movff	xC+0,SSP1BUF				; send battery offset
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	bra	I2C_PEN						; stop condition (and return)
    

;-----------------------------------------------------------------------------
; Read Gauge IC - Reset Accumulating Register to 0xFFFF
;
	global	lt2942_charge_done
lt2942_charge_done:
        btfsc	battery_gauge_type			; =1: Gauge IC LTC2959, =0: LT2942
	bra	lt2959_charge_done

	movlw	0x02						; point to accumulated charge registers
	rcall	I2C_TX_GAUGE				; send byte to the LT2942 gauge IC
	setf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	setf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	bra	I2C_PEN						; stop condition (and return)

lt2959_charge_done:
	; Reset Accumulating Register to 0x009EFF61 (0xFFFF * .159)
	movlw	0x03						; point to accumulated charge registers
	rcall	I2C_TX_GAUGE				; send byte to the LT2942 gauge IC
	movlw	0x00
	movwf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movlw	0x9E
	movwf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movlw	0xFF
	movwf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	movlw	0x61
	movwf	SSP1BUF						; data byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_Check_ACK				; check for acknowledge by receiver
	bra	I2C_PEN						; stop condition (and return)

	
;-----------------------------------------------------------------------------
; Helper Function - send 1 Byte to the LT2942 Gauge IC
;
I2C_TX_GAUGE:
	movwf	i2c_temp2					; save data byte to be sent
	rcall	I2C_SEN						; start condition
	movlw	0xC8						; address byte + Write bit LT2942
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	movlw	0xC6						; address byte + Write bit LTC2559
	rcall	I2C_TX						; send byte
	movf	i2c_temp2,W					; restore data byte to be sent
	bra	I2C_TX						; send byte and return


;-----------------------------------------------------------------------------
; Helper Function - receive 1 Byte from the LT2942 Gauge IC
;
I2C_RX_GAUGE:
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0xC9	    					; address byte + Read bit LT2942
	btfsc	battery_gauge_type				; =1: Gauge IC LTC2959, =0: LT2942
	movlw	0xC7						; address byte + Read bit LTC2959
	rcall	I2C_TX						; send byte
	bra	I2C_RCEN					; enable receive mode


;-----------------------------------------------------------------------------
; Reset Hardware and Software Battery Gauge
;
; called from comm.asm and menu_tree.asm
;
	global	reset_battery_gauge_and_lt2942
reset_battery_gauge_and_lt2942:
	btfsc	battery_gauge_available			; battery gauge chip available?
	call	lt2942_charge_done			; YES - reset meter to 0xFFFF
	;bra	reset_battery_gauge			; continue resetting gauge registers


;-----------------------------------------------------------------------------
; Reset Software Battery Gauge
;
	global	reset_battery_gauge
reset_battery_gauge:
	bsf		block_battery_gauge			; suspend ISR from accessing the battery registers
	movlw	.100						; set battery level to 100%
	movwf	batt_percent				; ...
	banksel	battery_gauge				; select bank ISR data
	clrf	battery_gauge+0				; null the battery registers
	clrf	battery_gauge+1				; ...
	clrf	battery_gauge+2				; ...
	clrf	battery_gauge+3				; ...
	clrf	battery_gauge+4				; ...
	clrf	battery_gauge+5				; ...
	banksel	charge_cycles
	clrf	charge_cycles+0				; null the charge cycles
	clrf	charge_cycles+1				; ...
	banksel	common						; back to bank common
	goto	eeprom_battery_gauge_write	; update battery registers in EEPROM, unblock ISR and return



 IFDEF _rx_functions

;-----------------------------------------------------------------------------
; OSTC TR - probe if TR Module available
;
	global	I2C_probe_OSTC_rx
I2C_probe_OSTC_rx:
	bcf		ostc_rx_present				; default to no TR module available
	clrf	WREG						; bank-safe set to zero of ...
	movff	WREG,rx_firmware_cur_major	; ... current TR module firmware, major
	movff	WREG,rx_firmware_cur_minor	; ... current TR module firmware, minor
	movlw	.5							; max number of tries for detecting a TR module
	movwf	hy							; initialize loop counter for tries
I2C_probe_OSTC_rx_1:
	rcall	I2C_SEN						; start condition
	movlw	0x50						; address byte + write bit
	rcall	I2C_TX						; send byte
	bsf		ostc_rx_present				; YES - TR module detected
	rcall	I2C_PEN						; stop condition
	btfss	ostc_rx_present				; was a TR module detected?
	return								; NO  - done

	WAITMS	.1							; wait 1 ms
	rcall	I2C_SEN						; start condition
	movlw	0x50						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x1B						; command: get firmware
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	WAITMS	.1							; wait 1 ms

	rcall	I2C_SEN						; start condition
	movlw	0x51						; address byte + Read bit
	movwf	SSP1BUF						; control byte
	rcall	WaitMSSP					; wait for TX to complete
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,rx_firmware_cur_major ; store as firmware version, major
	rcall	I2C_ACKEN					; send master acknowledge

	; last byte in read from RX circuity always with a NACK!
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,rx_firmware_cur_minor ; store as firmware version, minor
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	
	; wait for TR module becoming ready
	movff	rx_firmware_cur_minor,i2c_temp1	; copy minor firmware version to bank common
	movlw	.147							; code for not ready, minor
	cpfseq	i2c_temp1						; equal?
	return									; NO  - TR module ready, done
	movff	rx_firmware_cur_major,i2c_temp1 ; YES - copy major firmware version to bank common
	movlw	.27								;     - code for not ready, major
	cpfseq	i2c_temp1						;     - equal?
	return									;       NO  - TR module ready, done
	bsf		active_reset_ostc_rx			;       YES - apply reset to TR module
	WAITMS	.5								;           - wait 5 ms
	bcf		active_reset_ostc_rx			;           - release reset
	WAITMS	.250							;           - wait for     250 ms
	WAITMS	.250							;           - wait another 250 ms
	decfsz	hy,F							;           - decrement counter for number of tries, became zero?
	bra		I2C_probe_OSTC_rx_1				;           - NO  - try again
	bcf		ostc_rx_present					;           - YES - something is wrong, flag TR module as not available
	return									;                 - done


;-----------------------------------------------------------------------------
; OSTC TR - get Tank Data
;
	global	I2C_get_tankdata
I2C_get_tankdata:
	rcall	I2C_SEN						; start condition
	movlw	0x50						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x1E						; read buffer2 (48 bytes)
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition

	WAITMS	.1							; wait 1 ms

	; read 48 bytes
	rcall	I2C_SEN						; start condition
	movlw	0x51						; address byte + read bit
	rcall	I2C_TX						; send byte
	movlw	.47							; 47 with ACK + 1 w/o ACK
	movwf	i2c_temp2					; initialize loop counter
	lfsr	FSR2,rx_buffer				; point to start of rx data buffer 
I2C_get_tankdata_loop_read:
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,POSTINC2			; copy received byte to the rx buffer
	bcf		SSP1CON2,ACKDT				; reset ACKDT flag
	rcall	I2C_ACKEN					; send master acknowledge
	decfsz	i2c_temp2,F					; decrement loop counter, done?
	bra		I2C_get_tankdata_loop_read	; NO  - loop
	; read last byte without ACK
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,POSTINC2			; copy received byte to the rx buffer
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	return							; done



;-----------------------------------------------------------------------------
; OSTC TR - Firmware Update
;
 IFDEF _rx_update

	global	I2C_update_OSTC_rx
I2C_update_OSTC_rx:						; transfer 64 byte to RX co-processor
	; setup for write
	bcf		i2c_error_flag				; clear error flag
	lfsr	FSR2,buffer					; initialize pointer to send buffer used for verify
	movlw	.64							; initialize loop counter: 64 byte with ACK
	movwf	i2c_temp2					; ...
	; address write
	rcall	I2C_SEN						; start condition
	movlw	0x50						; address byte + write bit
	rcall	I2C_TX						; send byte
	; write 64 bytes
I2C_update_OSTC_loop:
	TBLRD*+								; read a byte from program memory
	movff	TABLAT,POSTINC2				; copy to send buffer
	movf	TABLAT,W				; copy to W
	rcall	I2C_TX						; send byte
	decfsz	i2c_temp2,F					;decrement loop counter, became zero?
	bra		I2C_update_OSTC_loop		; NO  - loop
	rcall	I2C_PEN						; stop condition
	WAITMS	.1							;     - wait another 1 ms
	; setup for read-back
	lfsr	FSR2,buffer					; reset pointer to begin of send buffer
	movlw	.63							; initialize loop counter: 63 byte with ACK + 1 w/o ACK
	movwf	i2c_temp2					; ...
	; address read-back
	rcall	I2C_SEN						; start condition
	movlw	0x51						; address byte + read bit
	rcall	I2C_TX						; send byte
	; read-back 64 bytes
I2C_update_OSTC_loop_read:
	rcall	I2C_RCEN					; enable receive mode
	movf	SSP1BUF,W					; copy received byte to WREG
	cpfseq	POSTINC2					; compare read-back byte with sent byte, equal?
	bsf		i2c_error_flag				; NO  - not equal, set error flag
	bcf		SSP1CON2,ACKDT				; reset ACKDT flag
	rcall	I2C_ACKEN					; send master acknowledge
	decfsz	i2c_temp2,F					; decrement loop counter, became zero?
	bra		I2C_update_OSTC_loop_read	; NO  - loop
	; 1 w/o ACK
	bsf		SSP1CON2, RCEN				; YES - enable receive mode
	rcall	WaitMSSP					;     - wait for TX to complete
	movf	SSP1BUF,W					;     - get 64th byte
	cpfseq	POSTINC2					;     - compare read-back byte with sent byte, equal?
	bsf		i2c_error_flag				;       NO  - not equal, set error flag
	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	WAITMS	.1
	; address commit
	rcall	I2C_SEN						; start condition
	movlw	0x50						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x1F						; write command
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	WAITMS	.5							; required waiting time
	; error check
	btfss	i2c_error_flag				; did an error occur?
	retlw	.0							; NO  - data transfered successfully
	retlw	.255						; YES - error in data transfer occurred

 ENDIF	; _rx_update

 ENDIF	; _rx_functions
 
;-----------------------------------------------------------------------------
; Probe for MS5837 sensor
;
 	global	I2C_probe_pressure_sensor	; Do not call from ISR!
I2C_probe_pressure_sensor:						; Probe the type of sensor, set/clear press_sensor_type
	bcf	press_sensor_type				; MS5541 as default
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	movwf	SSP1BUF						; control byte
	rcall	WaitMSSP					; wait for TX to complete
	; we need the ACKSTAT bit! Do not use I2C_TX routine here which might reset this bit!
	btfss	SSP1CON2,ACKSTAT				; ACK received?
	bsf	press_sensor_type				; MS5837 sensor found
	bra	I2C_PEN						; stop condition
 
;--------------------------------------------------------------------
; Helper Function - get the calibration parameter from # WREG address
; Do not call from ISR!
I2C_get_calib_parameter:
	movwf	lo						; store address
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movf	lo,W						; Point to calibration register
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	
	rcall	I2C_SEN						; start condition
	movlw	0xED					; address byte + read bit
	rcall	I2C_TX						; send byte 
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,dMSB				; High byte
	rcall	I2C_ACKEN					; send master acknowledge

	rcall	I2C_OneByteRX_NACK			; receive last byte with not acknowledge
	movff	SSP1BUF,dLSB				; Low byte
	bra	I2C_PEN						; stop condition
    
	
	global	I2C_get_calib_MS5837 ; Do not call from ISR!
I2C_get_calib_MS5837:	
	banksel	common
	; first, send a reset
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x1E
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	WAITMS	.5						; 2.8ms according to datasheet
	
	movlw	0xA2						; Point to C1
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C1+0						; store calib
	movff	dMSB,C1+1						; store calib

	movlw	0xA4						; Point to C2
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C2+0						; store calib
	movff	dMSB,C2+1						; store calib

	movlw	0xA6						; Point to C3
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C3+0						; store calib
	movff	dMSB,C3+1						; store calib

	movlw	0xA8						; Point to C4
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C4+0						; store calib
	movff	dMSB,C4+1						; store calib

	movlw	0xAA						; Point to C5
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C5+0						; store calib
	movff	dMSB,C5+1						; store calib

	movlw	0xAC						; Point to C6
	rcall	I2C_get_calib_parameter				; returns calibration value in lo and hi
    	movff	dLSB,C6+0						; store calib
	movff	dMSB,C6+1						; store calib
	
	return

	global	I2C_get_press_val_MS5837
I2C_get_press_val_MS5837:
    	btfsc	i2c_reinit_sensor2				; Sensor ok?
	rcall	I2CReset					; Try a I2C reset first
	btfsc	i2c_reinit_sensor2				; Sensor ok?
	bra	I2C_get_press_val_MS5837_skip			; We did a reset, restart conversion first
	
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x00						; command byte (0x00, read ADC)
	rcall	I2C_TX						; send byte
	
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0xED					; address byte + read bit
	rcall	I2C_TX						; send byte

	bsf	i2c_busy_pressure				; reading new pressure
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D1_buffer+2					; Upper byte
	rcall	I2C_ACKEN					; send master acknowledge
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D1_buffer+1					; high byte
	rcall	I2C_ACKEN					; send master acknowledge
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D1_buffer+0					; Low byte

	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	bcf	i2c_busy_pressure				; reading new pressure done.

I2C_get_press_val_MS5837_skip:	
	; Start temperature measurement
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x58						; OSR=4096, type=D2
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	bcf	ms5837_state					; =0: result of temperature will be in the ADC
	bcf	i2c_reinit_sensor2				; Clear error flag
    	return
	
	global	I2C_get_temp_val_MS5837	
I2C_get_temp_val_MS5837:
	btfsc	i2c_reinit_sensor2				; Sensor ok?
	rcall	I2CReset					; Try a I2C reset first
	btfsc	i2c_reinit_sensor2				; Sensor ok?
	bra	I2C_get_temp_val_MS5837_skip			; We did a reset, restart conversion first
	
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x00						; command byte (0x00, read ADC)
	rcall	I2C_TX						; send byte
	
	rcall	I2C_RSEN					; repeated start condition	
	movlw	0xED					; address byte + read bit
	rcall	I2C_TX						; send byte

	bsf	i2c_busy_temperature				; reading new temperature
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D2_buffer+2					; Upper byte
	rcall	I2C_ACKEN					; send master acknowledge
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D2_buffer+1					; high byte
	rcall	I2C_ACKEN					; send master acknowledge
	rcall	I2C_RCEN					; enable receive mode
	movff	SSP1BUF,D2_buffer+0					; Low byte

	rcall	I2C_MasterNotAckStop				; Master NOT acknowledge and Stop
	bcf	i2c_busy_temperature				; reading new temperature done.

I2C_get_temp_val_MS5837_skip:	
	; Start pressure measurement
	rcall	I2C_SEN						; start condition
	movlw	0xEC						; address byte + write bit
	rcall	I2C_TX						; send byte
	movlw	0x48						; OSR=4096, type=D1
	rcall	I2C_TX						; send byte
	rcall	I2C_PEN						; stop condition
	bsf	ms5837_state					; =0: result of pressure will be in the ADC
	bcf	i2c_reinit_sensor2				; Clear error flag
	return
	
	
;-----------------------------------------------------------------------------
; I2C Bus error checker 
;
	global	check_i2c_error
	extern TFT_message_i2c_error
check_i2c_error:
	btfss	i2c_error_flag
	return
	bcf	i2c_error_flag_lock				; arm error vault again
	incf	message_counter,F				; increase message counter
	goto	TFT_message_i2c_error				; show message for battery low (battery percent) and return

;-----------------------------------------------------------------------------	
	END