@@ -95,6 +95,8 @@ uint8_t scanForAttachedI2CDevice(void);
9595bool testReadAndPrint ();
9696
9797void TogglePin (uint8_t aPinNr);
98+
99+ #define I2C_RETRY_DELAY_MILLIS 10 // 5 was successful for me
98100uint16_t readWord (uint8_t aCommand);
99101void writeWord (uint8_t aCommand, uint16_t aValue);
100102int readWordFromManufacturerAccess (uint16_t aManufacturerCommand);
@@ -149,17 +151,19 @@ const char Current[] PROGMEM = "Current";
149151const char Average_Current_of_last_minute[] PROGMEM = " Average current of last minute" ;
150152const char Temperature[] PROGMEM = " Temperature" ;
151153
152- #define VOLTAGE_PRINT_DELTA_MILLIVOLT 5
154+ #define VOLTAGE_PRINT_DELTA_MILLIVOLT 5 // Print only if changed by two ore more mV
155+ #define VOLTAGE_PRINT_DELTA_MILLIAMPERE 2 // Print only if changed by two ore more mA
156+ #define VOLTAGE_PRINT_DELTA_MILLIDEGREE 100 // Print only if changed by 0.1 ore more degree
153157
154158struct SBMFunctionDescriptionStruct sSBMDynamicFunctionDescriptionArray [] = { {
155159FULL_CHARGE_CAPACITY, Full_Charge_Capacity, &printCapacity, " " }/* DescriptionLCD must be not NULL */ , {
156160REMAINING_CAPACITY, Remaining_Capacity, &printCapacity, " remCapacity" }, {
157161RELATIVE_SOC, Relative_Charge, &printPercentage, " rel charge " }, {
158162ABSOLUTE_SOC, Absolute_Charge, &printPercentage }, {
159163VOLTAGE, Voltage, &printVoltage, " " , VOLTAGE_PRINT_DELTA_MILLIVOLT } /* DescriptionLCD must be not NULL */ , {
160- CURRENT, Current, &printCurrent, " " , 1 } /* DescriptionLCD must be not NULL */ , {
164+ CURRENT, Current, &printCurrent, " " , VOLTAGE_PRINT_DELTA_MILLIAMPERE } /* DescriptionLCD must be not NULL */ , {
161165AverageCurrent, Average_Current_of_last_minute, &printCurrent }, {
162- TEMPERATURE, Temperature, &printTemperature, NULL , 100 }, {
166+ TEMPERATURE, Temperature, &printTemperature, NULL , VOLTAGE_PRINT_DELTA_MILLIDEGREE }, {
163167RUN_TIME_TO_EMPTY, Minutes_remaining_until_empty, &printTime, " min to empty " }, {
164168AVERAGE_TIME_TO_EMPTY, Average_minutes_remaining_until_empty, &printTime }, {
165169TIME_TO_FULL, Minutes_remaining_for_full_charge, &printTime, " min to full " }, {
@@ -188,7 +192,7 @@ STATE_OF_HEALTH, State_of_Health } };
188192bool sCapacityModePower ; // false = current, true = power
189193uint16_t sDesignVoltage ; // to retrieve last value for mWh to mA conversion
190194uint16_t sDesignCapacity ; // to compute relative capacity percent
191- uint16_t sCurrent ; // to decide if print "time to" values
195+ int16_t sCurrent ; // to decide if print "time to" values
192196uint8_t sGlobalReadError ;
193197uint8_t sLastGlobalReadError ;
194198
@@ -290,6 +294,8 @@ void loop() {
290294 printFunctionDescriptionArray (sSBMDynamicFunctionDescriptionArray ,
291295 (sizeof (sSBMDynamicFunctionDescriptionArray ) / sizeof (SBMFunctionDescriptionStruct)), true );
292296 printSBMNonStandardInfo (true );
297+
298+ // clear the display of 'H' for sGlobalReadError
293299 myLCD.setCursor (19 , 0 );
294300 myLCD.print (' ' );
295301 } else {
@@ -305,10 +311,12 @@ void loop() {
305311 Serial.print (F (" \r\n sGlobalReadError changed to: " ));
306312 Serial.println (sGlobalReadError );
307313 Serial.flush ();
314+
308315 if (sGlobalReadError == 0 ) {
316+ // print info again
309317 printInitialInfo ();
310-
311318 } else {
319+ // display 'H' for sGlobalReadError
312320 myLCD.setCursor (19 , 0 );
313321 myLCD.print (' H' );
314322 }
@@ -426,12 +434,7 @@ void printInitialInfo() {
426434 Serial.flush ();
427435}
428436
429- /*
430- * First write the command/function address byte, then read the word value for this function
431- * From the BQ spec: The processor then sends the bq2060 device address of 0001011 (bits 71)
432- * plus a R/W bit (bit 0) followed by an SMBus command code.
433- */
434- uint16_t readWord (uint8_t aCommand) {
437+ void writeCommandWithRetry (uint8_t aCommand) {
435438 Wire.beginTransmission (sI2CDeviceAddress );
436439 Wire.write (aCommand);
437440 sGlobalReadError = Wire.endTransmission (false ); // do not send stop, is required for some packs
@@ -443,12 +446,27 @@ uint16_t readWord(uint8_t aCommand) {
443446 * 4 .. other twi error (lost bus arbitration, bus error, ..)
444447 * 5 .. timeout
445448 */
449+ if (sGlobalReadError == 2 ) {
450+ delay (I2C_RETRY_DELAY_MILLIS);
451+ // Try again
452+ Wire.beginTransmission (sI2CDeviceAddress );
453+ Wire.write (aCommand);
454+ sGlobalReadError = Wire.endTransmission (false ); // do not send stop, is required for some packs
455+ }
456+ }
457+
458+ /*
459+ * First write the command/function address byte, then read the word value for this function
460+ * From the BQ spec: The processor then sends the bq2060 device address of 0001011 (bits 71)
461+ * plus a R/W bit (bit 0) followed by an SMBus command code.
462+ */
463+ uint16_t readWord (uint8_t aCommand) {
464+ writeCommandWithRetry (aCommand);
446465 if (sGlobalReadError != 0 ) {
447466#ifdef DEBUG
448467 Serial.print (F (" Error at I2C access: " ));
449468 Serial.println (sGlobalReadError );
450469#endif
451- // Wire.endTransmission(true);
452470 return 0xFFFF ;
453471 } else {
454472 Wire.requestFrom (sI2CDeviceAddress , (uint8_t ) 2 );
@@ -478,9 +496,7 @@ int readWordFromManufacturerAccess(uint16_t aManufacturerCommand) {
478496}
479497
480498uint8_t readBlock (uint8_t aCommand, uint8_t *aDataBufferPtr, uint8_t aDataBufferLength) {
481- Wire.beginTransmission (sI2CDeviceAddress );
482- Wire.write (aCommand);
483- Wire.endTransmission (false );
499+ writeCommandWithRetry (aCommand);
484500 Wire.requestFrom (sI2CDeviceAddress , (uint8_t ) 1 );
485501
486502// First read length of data
@@ -491,6 +507,7 @@ uint8_t readBlock(uint8_t aCommand, uint8_t *aDataBufferPtr, uint8_t aDataBuffer
491507 Serial.print (F (" tLengthOfData=" ));
492508 Serial.println (tLengthOfData);
493509#endif
510+ aDataBufferLength = aDataBufferLength - 1 ; // we read later with tLengthOfData + 1
494511
495512 if (tLengthOfData > aDataBufferLength) {
496513 Serial.println ();
@@ -505,9 +522,8 @@ uint8_t readBlock(uint8_t aCommand, uint8_t *aDataBufferPtr, uint8_t aDataBuffer
505522 /*
506523 * It is foolproof to start a new transmission here
507524 */
508- Wire.beginTransmission (sI2CDeviceAddress );
509- Wire.write (aCommand);
510- Wire.endTransmission (false );
525+ writeCommandWithRetry (aCommand);
526+
511527#ifdef DEBUG
512528 uint8_t tNumberOfDataReceived = Wire.requestFrom (sI2CDeviceAddress , (uint8_t ) (tLengthOfData + 1 )); // +1 since the length is read again
513529 Serial.print (F (" tNumberOfDataReceived=" ));
@@ -648,7 +664,7 @@ void printCapacity(struct SBMFunctionDescriptionStruct *aSBMFunctionDescription,
648664 if (sCapacityModePower ) {
649665 // print also mA since changing capacity mode did not work
650666 Serial.print (" | " );
651- uint8_t tCapacityCurrent = (aCapacity * 10000L ) / sDesignVoltage ;
667+ uint16_t tCapacityCurrent = (aCapacity * 10000L ) / sDesignVoltage ;
652668 Serial.print (tCapacityCurrent);
653669 Serial.print (StringCapacityModeCurrent);
654670 Serial.print (' h' );
@@ -697,9 +713,6 @@ void printCapacity(struct SBMFunctionDescriptionStruct *aSBMFunctionDescription,
697713 }
698714}
699715
700- /*
701- * Print only if changed by two ore more mV
702- */
703716void printVoltage (struct SBMFunctionDescriptionStruct *aSBMFunctionDescription, uint16_t aVoltage) {
704717 Serial.print ((float ) aVoltage / 1000 , 3 );
705718 Serial.print (" V" );
@@ -722,27 +735,22 @@ void printVoltage(struct SBMFunctionDescriptionStruct *aSBMFunctionDescription,
722735 }
723736}
724737
725- /*
726- * Print only if changed by two ore more mA
727- */
728738void printCurrent (struct SBMFunctionDescriptionStruct *aSBMFunctionDescription, uint16_t aCurrent) {
729- sCurrent = aCurrent;
739+ int tCurrent = (int ) aCurrent; // current can be negative
740+ sCurrent = tCurrent;
730741
731- Serial.print (( int ) aCurrent );
742+ Serial.print (tCurrent );
732743 Serial.print (" mA" );
733744 if (aSBMFunctionDescription->DescriptionLCD != NULL ) {
734745 // print 7 character from 12 to 18
735746 myLCD.setCursor (9 , 0 );
736747 myLCD.print (" " ); // clear old value from 9 to 19 incl. leading and trailing spaces
737748 myLCD.setCursor (12 , 0 );
738- myLCD.print (( int ) aCurrent );
749+ myLCD.print (tCurrent );
739750 myLCD.print (" mA" );
740751 }
741752}
742753
743- /*
744- * Print only if changed by more than 0.1 C
745- */
746754void printTemperature (struct SBMFunctionDescriptionStruct *aSBMFunctionDescription, uint16_t aTemperature) {
747755 Serial.print ((float ) (aTemperature / 10.0 ) - 273.15 );
748756 Serial.print (" C" );
@@ -757,27 +765,30 @@ void printTime(struct SBMFunctionDescriptionStruct *aSBMFunctionDescription, uin
757765 if (aMinutes >= 0xFFFE ) {
758766 Serial.print (F (" Battery not being (dis)charged" ));
759767 } else {
760- uint16_t tHour;
761- if (aMinutes >= 60 ) {
762- tHour = aMinutes / 60 ;
768+
769+ // Hours
770+ uint16_t tHour = aMinutes / 60 ;
771+ if (tHour > 0 ) {
763772 Serial.print (tHour);
764773 Serial.print (" h " );
765774 if (aSBMFunctionDescription->DescriptionLCD != NULL && sCurrent != 0 ) {
766775 // clip LCD display at 99h59min
767776 if (aMinutes > ((100 * 60 ) - 1 )) {
768777 tHour = 99 ;
769778 }
770- LCDClearLine (1 );
779+ LCDClearLine (2 );
771780 myLCD.print (tHour);
772781 myLCD.print (" h " );
773782 }
774783 aMinutes = aMinutes % 60 ;
775784 }
785+
786+ // Minutes
776787 Serial.print (aMinutes);
777788 Serial.print (" min" );
778789 if (aSBMFunctionDescription->DescriptionLCD != NULL && sCurrent != 0 ) {
779790 if (tHour == 0 ) {
780- LCDClearLine (1 );
791+ LCDClearLine (2 );
781792 }
782793
783794 myLCD.print (aMinutes);
@@ -870,16 +881,16 @@ void printBatteryStatus(struct SBMFunctionDescriptionStruct *aSBMFunctionDescrip
870881 * Status Bits
871882 */
872883 if (aStatus & INITIALIZED) {
873- prettyPrintlnValueDescription (F (" - Initialized" ));
884+ prettyPrintlnValueDescription (F (" 80 Initialized" ));
874885 }
875886 if (aStatus & DISCHARGING) {
876- prettyPrintlnValueDescription (F (" - Discharging" ));
887+ prettyPrintlnValueDescription (F (" 40 Discharging" ));
877888 }
878889 if (aStatus & FULLY_CHARGED) {
879- prettyPrintlnValueDescription (F (" - Fully Charged" ));
890+ prettyPrintlnValueDescription (F (" 20 Fully Charged" ));
880891 }
881892 if (aStatus & FULLY_DISCHARGED) {
882- prettyPrintlnValueDescription (F (" - Fully Discharged" ));
893+ prettyPrintlnValueDescription (F (" 10 Fully Discharged" ));
883894 }
884895}
885896
@@ -963,6 +974,10 @@ void printSBMManufacturerInfo(void) {
963974 Serial.println (" V" );
964975 Serial.println ();
965976
977+ } else if (tType == 2072 ) {
978+ Serial.print (F (" Controller IC identified by device type: " ));
979+ Serial.println (F (" bq8011/bq8015)" ));
980+
966981 } else if (tType == 2084 ) {
967982 Serial.print (F (" Controller IC identified by device type: " ));
968983 Serial.println (F (" bq2084" ));
0 commit comments