Mercurial > public > hwos_code
diff 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 diff
--- a/src/i2c.asm Mon Apr 29 13:05:18 2024 +0200 +++ b/src/i2c.asm Thu Nov 27 18:32:58 2025 +0100 @@ -42,6 +42,11 @@ ; ------------- ; 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 ; ----------- @@ -120,15 +125,12 @@ ;bra I2C_RX_accelerometer_compass0 ; NO - compass0 then ;I2C_RX_accelerometer_compass0: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x38 ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x00 ; ?? rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x39 ; address rcall I2C_TX ; send byte rcall I2C_OneByteRX ; get status byte @@ -170,9 +172,7 @@ rcall I2C_OneByteRX ; receive 1 byte with acknowledge movff SSP1BUF,hi ; copy data byte to hi - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete - ; according to data sheet there should be no master acknowledge for the last byte (accel_DZ+0)... + 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 @@ -180,21 +180,16 @@ btfsc STATUS,C ; carry to propagate? incf hi,F ; YES - do it MOVII mpr,accel_DZ ; copy result to accel_DZ - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return + bra I2C_PEN ; stop condition I2C_RX_accelerometer_compass1: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw b'10101000' ; 0x28 with auto-increment (MSB=1) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x3D ; address I2C_RX_accelerometer_common: ; common part for compass 1,2 and 3 @@ -260,12 +255,9 @@ MOVII mpr,accel_DY ; copy result rcall I2C_OneByteRX ; receive 1 byte with acknowledge movff SSP1BUF,lo ; accel_DZ+0 - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete - ; according to data sheet there should be no master Acknowledge for the last byte (accel_DZ+1)... + rcall I2C_OneByteRX_NACK ; receive last byte with not acknowledge movff SSP1BUF,hi ; accel_DZ+1 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + 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 ; ... @@ -276,41 +268,26 @@ I2C_RX_accelerometer_compass2: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x32 ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw b'10101000' ; 0x28 with auto-increment (MSB=1) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x33 ; address bra I2C_RX_accelerometer_common ; continue with common part I2C_RX_accelerometer_compass3: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3A ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x28 ; 0x28 (OUT_X_L_A) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x3B ; address bra I2C_RX_accelerometer_common ; continue with common part -;----------------------------------------------------------------------------- -; Helper Function - receive 1 Byte with Acknowledge -; -I2C_OneByteRX: - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,ACKEN ; send master acknowledge - bra WaitMSSP ; wait for TX to complete and return - ;----------------------------------------------------------------------------- ; Read Compass @@ -328,18 +305,14 @@ ;bra I2C_RX_compass0 ; NO - compass 0 then ;I2C_RX_compass0: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete - movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address + rcall I2C_SEN ; start condition + movlw 0x3C ; address + write bit rcall I2C_TX ; send byte - movlw 0x03 ; ?? + movlw 0x03 ; Point to Data Output X MSB Register (0x03) rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete - movlw 0x3D ; address + 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: @@ -383,11 +356,9 @@ movff SSP1BUF,compass_DZ+0 ; data byte rcall I2C_OneByteRX ; receive 1 byte with acknowledge movff SSP1BUF,compass_DX+1 ; data byte - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,compass_DX+0 ; data byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition btfss flip_screen ; 180° rotation? return ; NO - done banksel compass_DX ; YES - flip X @@ -400,15 +371,12 @@ I2C_RX_compass1: ; compass type 1 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw b'10001000' ; 0x08 with auto-increment (MSB=1) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x3D ; address rcall I2C_TX ; send byte ;rcall WaitMSSP ; TODO needed? (mH) @@ -444,27 +412,21 @@ I2C_RX_compass1_2: rcall I2C_OneByteRX ; receive 1 byte with acknowledge movff SSP1BUF,lo ; data byte - bsf SSP1CON2, RCEN ; Enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP - return ; done + bra I2C_PEN ; stop condition I2C_RX_compass2: ; compass type 2 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0xE8 ; 0x68 with auto-increment (MSB=1) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x3D ; address rcall I2C_TX ; send byte I2C_RX_compass2_xx: ; compass 3 joins in here @@ -499,26 +461,21 @@ MOVII mpr,compass_DY rcall I2C_OneByteRX ; receive 1 byte with acknowledge movff SSP1BUF,lo ; data byte - rcall I2C_OneByteRX ; receive 1 byte with acknowledge + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP - return ; done + bra I2C_PEN ; stop condition I2C_RX_compass3: ; compass type 3 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0xA8 ; 0x28 with auto-increment (MSB=1) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition (!) - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0x3D ; address rcall I2C_TX ; send byte bra I2C_RX_compass2_xx ; join with compass 2 code @@ -531,73 +488,85 @@ ; 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3A ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition btfsc compass_type3 ; compass 3 found? bra I2C_init_compass3 ; YES - initialize compass 3 ; probe for compass 2 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x32 ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address movwf SSP1BUF ; control byte rcall WaitMSSP ; wait for TX to complete - btfss SSP1CON2,ACKSTAT ; ACK received? + ; 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition btfsc compass_type2 ; compass 2 found? bra I2C_init_compass2 ; YES - initialize compass 2 - ; probe for compass 0 or 1 + ; probe for compass 1 bsf compass_type1 ; assume compass 1 by default - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x0F ; ?? rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition btfsc compass_type1 ; compass 1 found? bra I2C_init_compass1 ; YES - initialize compass 1 - ;bra I2C_init_compass0 ; NO - must be compass 0 then + + ; 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x00 ; ?? rcall I2C_TX ; send byte @@ -612,25 +581,20 @@ rcall I2C_TX ; send byte movlw b'00000000' ; select continuous mode rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition ; accelerometer rcall I2C_sleep_accelerometer0 ; registers can only be changed in standby mode - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x38 ; address - movff WREG,i2c_error_vault+0 ; Store 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition + rcall I2C_SEN ; start condition movlw 0x38 ; address rcall I2C_TX ; send byte movlw 0x2A ; CTRL_REG1 @@ -640,11 +604,9 @@ rcall I2C_TX ; send byte movlw b'00000010' ; CTRL_REG2: high-res in active mode rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x38 ; address rcall I2C_TX ; send byte movlw 0x2A ; CTRL_REG1 @@ -652,17 +614,13 @@ ; 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition I2C_init_compass1: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x9F ; 1F with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -697,19 +655,15 @@ rcall I2C_TX ; send byte movlw b'00000000' ; CTRL7 Continuous Mode rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition ; accelerometer initializes along with magnetic sensor I2C_init_compass2: ; magnetic - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0xE0 ; 0x60 with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -719,14 +673,11 @@ rcall I2C_TX ; send byte movlw b'00010000' ; CFG_REG_C_M BDU=1 0x62 0x57 rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition ; accelerometer - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x32 ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x9F ; 1F with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -742,17 +693,13 @@ rcall I2C_TX ; send byte ; movlw b'00000000' ; CTRL_REG5_A ; rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition I2C_init_compass3: ; magnetic - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0xA0 ; 0x20 with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -768,14 +715,11 @@ rcall I2C_TX ; send byte movlw b'00000000' ; CTRL_REG5_M 0x24 rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; Stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition ;accelerometer - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3A ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x20 rcall I2C_TX ; send byte @@ -787,18 +731,10 @@ rcall I2C_TX ; send byte movlw b'11001100' ; CTRL_REG4_A 0x23 rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition + -;----------------------------------------------------------------------------- -; 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 - rcall WaitMSSP ; wait for TX to complete - bra I2C_Check_ACK ; check for acknowledge by receiver and return - + ;----------------------------------------------------------------------------- ; Deactivate Compass / Accelerometer ; @@ -818,10 +754,8 @@ I2C_sleep_compass0: ; magnetic - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x00 ; ?? rcall I2C_TX ; send byte @@ -831,58 +765,45 @@ rcall I2C_TX ; send byte movlw b'00000010' ; idle mode rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition I2C_sleep_accelerometer0: ; accelerometer - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x38 ; address - movff WREG,i2c_error_vault+0 ; Store 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition I2C_sleep_compass1: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition ; accelerometer sleeps with magnetic sensor I2C_sleep_compass2: ; magnetic - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0xE0 ; 0x60 with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -894,14 +815,11 @@ rcall I2C_TX ; send byte movlw b'00000000' ; INT_CTRL_REG_M 0x63 rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition ; accelerometer - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x32 ; address - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x9F ; 1F with auto-increment (MSB=1) rcall I2C_TX ; send byte @@ -909,45 +827,121 @@ rcall I2C_TX ; send byte movlw b'00000000' ; CTRL_REG1_A 0x20 (all off) rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + bra I2C_PEN ; stop condition I2C_sleep_compass3: ; magnetic - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3C ; address - movff WREG,i2c_error_vault+0 ; Store 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition ; accelerometer - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x3A ; address - movff WREG,i2c_error_vault+0 ; Store 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + 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: - movff SSP1BUF,i2c_error_vault+1 + 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? @@ -965,12 +959,10 @@ ; I2C_MasterNotAckStop: bsf SSP1CON2,ACKDT ; set ACKDT flag - bsf SSP1CON2,ACKEN ; master NOT acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master NOT acknowledge bcf SSP1CON2,ACKDT ; reset ACKDT flag - bsf SSP1CON2,PEN ; stop condition - bra WaitMSSP ; wait for TX to complete + bra I2C_PEN ; stop condition ;----------------------------------------------------------------------------- ; Helper Function - check for Acknowledge by Receiver @@ -989,6 +981,7 @@ 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 @@ -1000,6 +993,7 @@ ; ; recover in case something went wrong, i.g. slave holds SDA low ; + global I2CReset I2CReset: clrf SSP1CON1 ; reset entire module clrf SSP1CON2 ; ... @@ -1028,7 +1022,7 @@ I2CReset_2: bsf TRISC,3 ; SCL as input clrf SSP1CON1 ; setup I2C mode - WAITMS d'10' ; wait 10 ms (reset-timeout for I2C devices) + rcall I2C_WAIT_100US ; ISR-Safe 100µs wait movlw b'00000000' ; enable slew rate control movwf SSP1STAT ; ... movlw b'00101000' ; configure I2C module @@ -1037,13 +1031,30 @@ movwf SSP1CON2 ; ... movlw i2c_speed_value movwf SSP1ADD ; ... - return ; done + 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 ; -lt2942_init_again: +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 @@ -1053,78 +1064,76 @@ movff battery_accumulated_charge+0,SSP1BUF ; data byte rcall WaitMSSP ; wait for TX to complete rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition MOVII battery_accumulated_charge,sub_a ; copy result to sub_a - ;bra lt2942_init ; and initialize again... + ;bra battery_gauge_init ; and initialize again... ;----------------------------------------------------------------------------- ; Initialize Gauge IC ; - global lt2942_init -lt2942_init: - movlw 0x01 ; point to control reg B - rcall I2C_TX_GAUGE ; send byte to the LT2942 gauge IC - movlw b'11111000' ; automatic conversion every two seconds - movwf SSP1BUF ; data byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done - -;----------------------------------------------------------------------------- -; Sleep Gauge IC -; - global lt2942_sleep -lt2942_sleep: - movlw 0x01 ; point to control reg B - rcall I2C_TX_GAUGE ; send byte to the LT2942 gauge IC - movlw b'00111000' ; sleep - movwf SSP1BUF ; data byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return ; done + 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_available ; clear flag - 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 + bcf battery_gauge_type ; =1: Gauge IC LTC2959, =0: LT2942 + bcf battery_gauge_available ; clear flag on default - bsf SSP1CON2,ACKDT ; set ACKDT flag - bsf SSP1CON2,ACKEN ; master NOT acknowledge + ; 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 - bcf SSP1CON2,ACKDT ; reset ACKDT flag - - movff SSP1BUF,WREG ; copy received byte to WREG - btfss WREG,7 ; 2942 found? - bsf battery_gauge_available ; YES - set flag - bsf SSP1CON2,PEN ; stop condition + ; 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 - return ; done - + ; 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 - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master acknowledge movff SSP1BUF,xA+1 ; copy received byte to xA+1 - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,xA+0 ; copy received byte to xA+0 rcall I2C_MasterNotAckStop ; Master NOT acknowledge and Stop @@ -1133,12 +1142,46 @@ 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,batt_voltage+0 ; divide by 65536 can easily be done by just taking the 3rd and 4th byte of the multiplication result - movff xC+3,batt_voltage+1 ; ... + 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 - tstfsz batt_voltage+1 ; < 256 mV ? - return ; NO - done - bra lt2942_init_again ; YES - initialize gauge and return + 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 ;----------------------------------------------------------------------------- @@ -1146,24 +1189,26 @@ ; 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 - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master acknowledge movff SSP1BUF,xA+1 ; store raw temperature, high byte - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 + ; 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 @@ -1189,43 +1234,43 @@ 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 + return ; - done +LTC2959_get_temperature: + return + ;----------------------------------------------------------------------------- ; Read Gauge IC - Read State of Charge ; - global lt2942_get_accumulated_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 - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master acknowledge movff SSP1BUF,gauge_status_byte ; copy received byte to gauge_status_byte - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete ; dummy read (control byte) - movf SSP1BUF,W ; dump to WREG - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode + movf SSP1BUF,W ; dump to WREG (Control) + rcall I2C_ACKEN ; send master acknowledge - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,sub_a+1 ; copy received byte to sub_a+1 - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master acknowledge - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 lt2942_init_again ; YES - do an re-initialization + 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) / 365 + ; 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 @@ -1240,12 +1285,64 @@ movlw .100 ; max. value is 100 % cpfslt batt_percent ; batt_percent < 100 % ? movwf batt_percent ; NO - limit to 100 % - movlw .95 ; < 95 % - cpfsgt batt_percent + 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 @@ -1254,16 +1351,40 @@ 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 - bsf SSP1CON2,PEN ; stop condition + 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 - return ; done - + 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 @@ -1272,40 +1393,55 @@ setf SSP1BUF ; data byte rcall WaitMSSP ; wait for TX to complete rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition + 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 - return ; done + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete - movlw 0xC8 ; address byte + Write bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + 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 + bra I2C_TX ; send byte and return ;----------------------------------------------------------------------------- ; Helper Function - receive 1 Byte from the LT2942 Gauge IC ; I2C_RX_GAUGE: - bsf SSP1CON2,RSEN ; repeated start condition - rcall WaitMSSP ; wait for TX to complete - movlw 0xC9 ; address byte + Read bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,RCEN ; enable receive mode - bra WaitMSSP ; wait for reception and return + 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 ;----------------------------------------------------------------------------- @@ -1315,7 +1451,7 @@ ; global reset_battery_gauge_and_lt2942 reset_battery_gauge_and_lt2942: - btfsc battery_gauge_available ; battery gauge chip available? + 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 @@ -1357,49 +1493,34 @@ movlw .5 ; max number of tries for detecting a TR module movwf hy ; initialize loop counter for tries I2C_probe_OSTC_rx_1: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x50 ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - btfss SSP1CON2,ACKSTAT ; ACK received? + rcall I2C_TX ; send byte bsf ostc_rx_present ; YES - TR module detected - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition btfss ostc_rx_present ; was a TR module detected? return ; NO - done WAITMS .1 ; wait 1 ms - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x50 ; address byte + write bit - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte movlw 0x1B ; command: get firmware - movwf SSP1BUF ; send command - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_TX ; send byte + rcall I2C_PEN ; stop condition WAITMS .1 ; wait 1 ms - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x51 ; address byte + Read bit movwf SSP1BUF ; control byte rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,rx_firmware_cur_major ; store as firmware version, major - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + rcall I2C_ACKEN ; send master acknowledge ; last byte in read from RX circuity always with a NACK! - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 @@ -1428,44 +1549,31 @@ ; global I2C_get_tankdata I2C_get_tankdata: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x50 ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte movlw 0x1E ; read buffer2 (48 bytes) - movwf SSP1BUF ; data byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_TX ; send byte + rcall I2C_PEN ; stop condition WAITMS .1 ; wait 1 ms ; read 48 bytes - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x51 ; address byte + read bit - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + 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: - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,POSTINC2 ; copy received byte to the rx buffer bcf SSP1CON2,ACKDT ; reset ACKDT flag - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 @@ -1485,46 +1593,35 @@ movlw .64 ; initialize loop counter: 64 byte with ACK movwf i2c_temp2 ; ... ; address write - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x50 ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + 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 - movff TABLAT,SSP1BUF ; copy to I2C data buffer - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + 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 - bsf SSP1CON2,PEN ; YES - stop condition - rcall WaitMSSP ; - wait for TX to complete + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x51 ; address byte + read bit - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte ; read-back 64 bytes I2C_update_OSTC_loop_read: - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete + 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 @@ -1536,18 +1633,12 @@ rcall I2C_MasterNotAckStop ; Master NOT acknowledge and Stop WAITMS .1 ; address commit - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0x50 ; address byte + write bit - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte movlw 0x1F ; write command - movwf SSP1BUF ; data byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + 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? @@ -1564,70 +1655,49 @@ 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0xEC ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete - return + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0xEC ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movf lo,W ; Point to calibration register rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0xED ; address byte + read bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception and return + rcall I2C_TX ; send byte + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,dMSB ; High byte - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete - - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception + rcall I2C_ACKEN ; send master acknowledge + + rcall I2C_OneByteRX_NACK ; receive last byte with not acknowledge movff SSP1BUF,dLSB ; Low byte -; bsf SSP1CON2,ACKDT ; set ACKDT flag - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete -; bcf SSP1CON2,ACKDT ; reset ACKDT flag - bsf SSP1CON2,PEN ; stop condition - bra WaitMSSP ; wait for TX to complete (And return) + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_SEN ; start condition movlw 0xEC ; address byte + write bit - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x1E rcall I2C_TX ; send byte - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_PEN ; stop condition WAITMS .5 ; 2.8ms according to datasheet movlw 0xA2 ; Point to C1 @@ -1664,98 +1734,86 @@ global I2C_get_press_val_MS5837 I2C_get_press_val_MS5837: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x00 ; command byte (0x00, read ADC) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0xED ; address byte + read bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte bsf i2c_busy_pressure ; reading new pressure - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception and return + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,D1_buffer+2 ; Upper byte - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception + rcall I2C_ACKEN ; send master acknowledge + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,D1_buffer+1 ; high byte - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + 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: - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - movff WREG,i2c_error_vault+0 ; Store address rcall I2C_TX ; send byte movlw 0x00 ; command byte (0x00, read ADC) rcall I2C_TX ; send byte - bsf SSP1CON2,RSEN ; repeated start condition - rcall WaitMSSP ; wait for TX to complete + rcall I2C_RSEN ; repeated start condition movlw 0xED ; address byte + read bit - movff WREG,i2c_error_vault+0 ; Store address - movwf SSP1BUF ; control byte - rcall WaitMSSP ; wait for TX to complete - rcall I2C_Check_ACK ; check for acknowledge by receiver + rcall I2C_TX ; send byte bsf i2c_busy_temperature ; reading new temperature - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception and return + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,D2_buffer+2 ; Upper byte - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception + rcall I2C_ACKEN ; send master acknowledge + rcall I2C_RCEN ; enable receive mode movff SSP1BUF,D2_buffer+1 ; high byte - bsf SSP1CON2,ACKEN ; master acknowledge - rcall WaitMSSP ; wait for TX to complete - bsf SSP1CON2,RCEN ; enable receive mode - rcall WaitMSSP ; wait for reception + 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 - bsf SSP1CON2,SEN ; start condition - rcall WaitMSSP ; wait for TX to complete + 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 - bsf SSP1CON2,PEN ; stop condition - rcall WaitMSSP ; wait for TX to complete + 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 @@ -1767,6 +1825,7 @@ 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
