KIT Solar Car Project / Mbed 2 deprecated BMS_ver1

Dependencies:   mbed INA226gfg

Committer:
MPPT51
Date:
Sat Jul 31 09:12:21 2021 +0000
Revision:
0:d92f936cf10d
commit_bms

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MPPT51 0:d92f936cf10d 1 /* Battery management system based on bq769x0 for ARM mbed
MPPT51 0:d92f936cf10d 2 * Copyright (c) 2015-2018 Martin Jäger (www.libre.solar)
MPPT51 0:d92f936cf10d 3 *
MPPT51 0:d92f936cf10d 4 * Licensed under the Apache License, Version 2.0 (the "License");
MPPT51 0:d92f936cf10d 5 * you may not use this file except in compliance with the License.
MPPT51 0:d92f936cf10d 6 * You may obtain a copy of the License at
MPPT51 0:d92f936cf10d 7 *
MPPT51 0:d92f936cf10d 8 * http://www.apache.org/licenses/LICENSE-2.0
MPPT51 0:d92f936cf10d 9 *
MPPT51 0:d92f936cf10d 10 * Unless required by applicable law or agreed to in writing, software
MPPT51 0:d92f936cf10d 11 * distributed under the License is distributed on an "AS IS" BASIS,
MPPT51 0:d92f936cf10d 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
MPPT51 0:d92f936cf10d 13 * See the License for the specific language governing permissions and
MPPT51 0:d92f936cf10d 14 * limitations under the License.
MPPT51 0:d92f936cf10d 15 */
MPPT51 0:d92f936cf10d 16
MPPT51 0:d92f936cf10d 17 #include <math.h> // log for thermistor calculation
MPPT51 0:d92f936cf10d 18
MPPT51 0:d92f936cf10d 19 #include "bq769x0.h"
MPPT51 0:d92f936cf10d 20 #include "registers.h"
MPPT51 0:d92f936cf10d 21 #include "mbed.h"
MPPT51 0:d92f936cf10d 22
MPPT51 0:d92f936cf10d 23 DigitalOut bms1_on(p8);
MPPT51 0:d92f936cf10d 24 DigitalOut bms2_on(p12);
MPPT51 0:d92f936cf10d 25
MPPT51 0:d92f936cf10d 26 const char *byte2char(int x)
MPPT51 0:d92f936cf10d 27 {
MPPT51 0:d92f936cf10d 28 static char b[9];
MPPT51 0:d92f936cf10d 29 b[0] = '\0';
MPPT51 0:d92f936cf10d 30
MPPT51 0:d92f936cf10d 31 int z;
MPPT51 0:d92f936cf10d 32 for (z = 128; z > 0; z >>= 1)
MPPT51 0:d92f936cf10d 33 {
MPPT51 0:d92f936cf10d 34 strcat(b, ((x & z) == z) ? "1" : "0");
MPPT51 0:d92f936cf10d 35 }
MPPT51 0:d92f936cf10d 36
MPPT51 0:d92f936cf10d 37 return b;
MPPT51 0:d92f936cf10d 38 }
MPPT51 0:d92f936cf10d 39
MPPT51 0:d92f936cf10d 40 uint8_t _crc8_ccitt_update (uint8_t inCrc, uint8_t inData)
MPPT51 0:d92f936cf10d 41 {
MPPT51 0:d92f936cf10d 42 uint8_t i;
MPPT51 0:d92f936cf10d 43 uint8_t data;
MPPT51 0:d92f936cf10d 44
MPPT51 0:d92f936cf10d 45 data = inCrc ^ inData;
MPPT51 0:d92f936cf10d 46
MPPT51 0:d92f936cf10d 47 for ( i = 0; i < 8; i++ )
MPPT51 0:d92f936cf10d 48 {
MPPT51 0:d92f936cf10d 49 if (( data & 0x80 ) != 0 )
MPPT51 0:d92f936cf10d 50 {
MPPT51 0:d92f936cf10d 51 data <<= 1;
MPPT51 0:d92f936cf10d 52 data ^= 0x07;
MPPT51 0:d92f936cf10d 53 }
MPPT51 0:d92f936cf10d 54 else
MPPT51 0:d92f936cf10d 55 {
MPPT51 0:d92f936cf10d 56 data <<= 1;
MPPT51 0:d92f936cf10d 57 }
MPPT51 0:d92f936cf10d 58 }
MPPT51 0:d92f936cf10d 59 return data;
MPPT51 0:d92f936cf10d 60 }
MPPT51 0:d92f936cf10d 61
MPPT51 0:d92f936cf10d 62 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 63
MPPT51 0:d92f936cf10d 64 //bq769x0::bms1_output(PinName bms1_on) : _pin(LED1) {
MPPT51 0:d92f936cf10d 65 // _Pin = 1;
MPPT51 0:d92f936cf10d 66 //}
MPPT51 0:d92f936cf10d 67 bq769x0::bq769x0(I2C& bqI2C, PinName alertPin, int bqType, int bqI2CAddress, bool crc):
MPPT51 0:d92f936cf10d 68 _i2c(bqI2C), _alertInterrupt(alertPin)
MPPT51 0:d92f936cf10d 69 {
MPPT51 0:d92f936cf10d 70 _timer.start();
MPPT51 0:d92f936cf10d 71 _alertInterrupt.rise(callback(this, &bq769x0::setAlertInterruptFlag));
MPPT51 0:d92f936cf10d 72
MPPT51 0:d92f936cf10d 73 // set some safe default values
MPPT51 0:d92f936cf10d 74 autoBalancingEnabled = false;
MPPT51 0:d92f936cf10d 75 balancingMinIdleTime_s = 1800; // default: 30 minutes
MPPT51 0:d92f936cf10d 76 idleCurrentThreshold = 30; // mA
MPPT51 0:d92f936cf10d 77
MPPT51 0:d92f936cf10d 78 thermistorBetaValue = 3435; // typical value for Semitec 103AT-5 thermistor
MPPT51 0:d92f936cf10d 79
MPPT51 0:d92f936cf10d 80 alertInterruptFlag = true; // init with true to check and clear errors at start-up
MPPT51 0:d92f936cf10d 81
MPPT51 0:d92f936cf10d 82 type = bqType;
MPPT51 0:d92f936cf10d 83 if (type == bq76920) {
MPPT51 0:d92f936cf10d 84 numberOfCells = 5;
MPPT51 0:d92f936cf10d 85 } else if (type == bq76930) {
MPPT51 0:d92f936cf10d 86 numberOfCells = 10;
MPPT51 0:d92f936cf10d 87 } else {
MPPT51 0:d92f936cf10d 88 numberOfCells = 15;
MPPT51 0:d92f936cf10d 89 }
MPPT51 0:d92f936cf10d 90
MPPT51 0:d92f936cf10d 91 // initialize variables
MPPT51 0:d92f936cf10d 92 for (int i = 0; i < numberOfCells - 1; i++) {
MPPT51 0:d92f936cf10d 93 cellVoltages[i] = 0;
MPPT51 0:d92f936cf10d 94 }
MPPT51 0:d92f936cf10d 95
MPPT51 0:d92f936cf10d 96 //init1();
MPPT51 0:d92f936cf10d 97 //init2();
MPPT51 0:d92f936cf10d 98
MPPT51 0:d92f936cf10d 99 //crcEnabled = crc;
MPPT51 0:d92f936cf10d 100 //I2CAddress = bqI2CAddress;
MPPT51 0:d92f936cf10d 101 /*
MPPT51 0:d92f936cf10d 102 if (determineAddressAndCrc())
MPPT51 0:d92f936cf10d 103 {
MPPT51 0:d92f936cf10d 104 // initial settings for bq769x0
MPPT51 0:d92f936cf10d 105 writeRegister(SYS_CTRL1, 0b00011000); // switch external thermistor and ADC on
MPPT51 0:d92f936cf10d 106 writeRegister(SYS_CTRL2, 0b01000000); // switch CC_EN on
MPPT51 0:d92f936cf10d 107
MPPT51 0:d92f936cf10d 108 // get ADC offset and gain
MPPT51 0:d92f936cf10d 109 adcOffset = (signed int) readRegister(ADCOFFSET); // convert from 2's complement
MPPT51 0:d92f936cf10d 110 adcGain = 365 + (((readRegister(ADCGAIN1) & 0b00001100) << 1) |
MPPT51 0:d92f936cf10d 111 ((readRegister(ADCGAIN2) & 0b11100000) >> 5)); // uV/LSB
MPPT51 0:d92f936cf10d 112
MPPT51 0:d92f936cf10d 113 printf("BMS OK\n");
MPPT51 0:d92f936cf10d 114 }
MPPT51 0:d92f936cf10d 115 else {
MPPT51 0:d92f936cf10d 116 // TODO: do something else... e.g. set error flag
MPPT51 0:d92f936cf10d 117 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 118 printf("BMS communication error\n");
MPPT51 0:d92f936cf10d 119 #endif
MPPT51 0:d92f936cf10d 120 }
MPPT51 0:d92f936cf10d 121 */
MPPT51 0:d92f936cf10d 122 }
MPPT51 0:d92f936cf10d 123
MPPT51 0:d92f936cf10d 124 void bq769x0::init1(void){
MPPT51 0:d92f936cf10d 125 bms1_on = 1;
MPPT51 0:d92f936cf10d 126 wait(1);
MPPT51 0:d92f936cf10d 127 printf("BMS1 init\n");
MPPT51 0:d92f936cf10d 128 _timer.reset();
MPPT51 0:d92f936cf10d 129
MPPT51 0:d92f936cf10d 130 if (determineAddressAndCrc())
MPPT51 0:d92f936cf10d 131 {
MPPT51 0:d92f936cf10d 132 printf("BMS1 init11\n");
MPPT51 0:d92f936cf10d 133 // initial settings for bq769x0
MPPT51 0:d92f936cf10d 134 writeRegister(SYS_CTRL1, 0b00011000); // switch external thermistor and ADC on
MPPT51 0:d92f936cf10d 135 printf("BMS1 init111\n");
MPPT51 0:d92f936cf10d 136 writeRegister(SYS_CTRL2, 0b01000000); // switch CC_EN on
MPPT51 0:d92f936cf10d 137 printf("BMS1 init111\n");
MPPT51 0:d92f936cf10d 138
MPPT51 0:d92f936cf10d 139 // get ADC offset and gain
MPPT51 0:d92f936cf10d 140 adcOffset1 = (signed int) readRegister(ADCOFFSET); // convert from 2's complement
MPPT51 0:d92f936cf10d 141 adcGain1 = 365 + (((readRegister(ADCGAIN1) & 0b00001100) << 1) |
MPPT51 0:d92f936cf10d 142 ((readRegister(ADCGAIN2) & 0b11100000) >> 5)); // uV/LSB
MPPT51 0:d92f936cf10d 143
MPPT51 0:d92f936cf10d 144 printf("BMS1 OK\n");
MPPT51 0:d92f936cf10d 145 }
MPPT51 0:d92f936cf10d 146 else {
MPPT51 0:d92f936cf10d 147 // TODO: do something else... e.g. set error flag
MPPT51 0:d92f936cf10d 148 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 149 printf("BMS1 communication error\n");
MPPT51 0:d92f936cf10d 150 #endif
MPPT51 0:d92f936cf10d 151 }
MPPT51 0:d92f936cf10d 152 bms1_on = 0;
MPPT51 0:d92f936cf10d 153 }
MPPT51 0:d92f936cf10d 154
MPPT51 0:d92f936cf10d 155 void bq769x0::init2(void){
MPPT51 0:d92f936cf10d 156 bms2_on = 1;
MPPT51 0:d92f936cf10d 157 wait(0.5);
MPPT51 0:d92f936cf10d 158
MPPT51 0:d92f936cf10d 159 printf("BMS2 init\n");
MPPT51 0:d92f936cf10d 160 _timer.reset();
MPPT51 0:d92f936cf10d 161
MPPT51 0:d92f936cf10d 162 if (determineAddressAndCrc())
MPPT51 0:d92f936cf10d 163 {
MPPT51 0:d92f936cf10d 164 // initial settings for bq769x0
MPPT51 0:d92f936cf10d 165 writeRegister(SYS_CTRL1, 0b00011000); // switch external thermistor and ADC on
MPPT51 0:d92f936cf10d 166 writeRegister(SYS_CTRL2, 0b01000000); // switch CC_EN on
MPPT51 0:d92f936cf10d 167 printf("BMS init 1\n");
MPPT51 0:d92f936cf10d 168
MPPT51 0:d92f936cf10d 169 // get ADC offset and gain
MPPT51 0:d92f936cf10d 170 adcOffset2 = (signed int) readRegister(ADCOFFSET); // convert from 2's complement
MPPT51 0:d92f936cf10d 171 adcGain2 = 365 + (((readRegister(ADCGAIN1) & 0b00001100) << 1) |
MPPT51 0:d92f936cf10d 172 ((readRegister(ADCGAIN2) & 0b11100000) >> 5)); // uV/LSB
MPPT51 0:d92f936cf10d 173
MPPT51 0:d92f936cf10d 174 printf("BMS2 OK\n");
MPPT51 0:d92f936cf10d 175 }
MPPT51 0:d92f936cf10d 176 else {
MPPT51 0:d92f936cf10d 177 // TODO: do something else... e.g. set error flag
MPPT51 0:d92f936cf10d 178 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 179 printf("BMS1 communication error\n");
MPPT51 0:d92f936cf10d 180 #endif
MPPT51 0:d92f936cf10d 181 }
MPPT51 0:d92f936cf10d 182 bms2_on = 0;
MPPT51 0:d92f936cf10d 183 }
MPPT51 0:d92f936cf10d 184 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 185 // automatically find out address and CRC setting
MPPT51 0:d92f936cf10d 186
MPPT51 0:d92f936cf10d 187 bool bq769x0::determineAddressAndCrc(void)
MPPT51 0:d92f936cf10d 188 {
MPPT51 0:d92f936cf10d 189 I2CAddress = 0x08;
MPPT51 0:d92f936cf10d 190 crcEnabled = true;
MPPT51 0:d92f936cf10d 191 writeRegister(CC_CFG, 0x19);
MPPT51 0:d92f936cf10d 192 if (readRegister(CC_CFG) == 0x19) {
MPPT51 0:d92f936cf10d 193 return true;
MPPT51 0:d92f936cf10d 194 }
MPPT51 0:d92f936cf10d 195
MPPT51 0:d92f936cf10d 196 I2CAddress = 0x18;
MPPT51 0:d92f936cf10d 197 crcEnabled = true;
MPPT51 0:d92f936cf10d 198 writeRegister(CC_CFG, 0x19);
MPPT51 0:d92f936cf10d 199 if (readRegister(CC_CFG) == 0x19) {
MPPT51 0:d92f936cf10d 200 return true;
MPPT51 0:d92f936cf10d 201 }
MPPT51 0:d92f936cf10d 202
MPPT51 0:d92f936cf10d 203 I2CAddress = 0x08;
MPPT51 0:d92f936cf10d 204 crcEnabled = false;
MPPT51 0:d92f936cf10d 205 writeRegister(CC_CFG, 0x19);
MPPT51 0:d92f936cf10d 206 if (readRegister(CC_CFG) == 0x19) {
MPPT51 0:d92f936cf10d 207 return true;
MPPT51 0:d92f936cf10d 208 }
MPPT51 0:d92f936cf10d 209
MPPT51 0:d92f936cf10d 210 I2CAddress = 0x18;
MPPT51 0:d92f936cf10d 211 crcEnabled = false;
MPPT51 0:d92f936cf10d 212 writeRegister(CC_CFG, 0x19);
MPPT51 0:d92f936cf10d 213 if (readRegister(CC_CFG) == 0x19) {
MPPT51 0:d92f936cf10d 214 return true;
MPPT51 0:d92f936cf10d 215 }
MPPT51 0:d92f936cf10d 216
MPPT51 0:d92f936cf10d 217 return false;
MPPT51 0:d92f936cf10d 218 }
MPPT51 0:d92f936cf10d 219
MPPT51 0:d92f936cf10d 220 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 221 // Boot IC by pulling the boot pin TS1 high for some ms
MPPT51 0:d92f936cf10d 222
MPPT51 0:d92f936cf10d 223 void bq769x0::boot(PinName bootPin)
MPPT51 0:d92f936cf10d 224 {
MPPT51 0:d92f936cf10d 225 DigitalInOut boot(bootPin);
MPPT51 0:d92f936cf10d 226
MPPT51 0:d92f936cf10d 227 boot = 1;
MPPT51 0:d92f936cf10d 228 wait_ms(5); // wait 5 ms for device to receive boot signal (datasheet: max. 2 ms)
MPPT51 0:d92f936cf10d 229 boot.input(); // don't disturb temperature measurement
MPPT51 0:d92f936cf10d 230 wait_ms(10); // wait for device to boot up completely (datasheet: max. 10 ms)
MPPT51 0:d92f936cf10d 231 }
MPPT51 0:d92f936cf10d 232
MPPT51 0:d92f936cf10d 233
MPPT51 0:d92f936cf10d 234 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 235 // Fast function to check whether BMS has an error
MPPT51 0:d92f936cf10d 236 // (returns 0 if everything is OK)
MPPT51 0:d92f936cf10d 237
MPPT51 0:d92f936cf10d 238 int bq769x0::checkStatus()
MPPT51 0:d92f936cf10d 239 {
MPPT51 0:d92f936cf10d 240 // printf("errorStatus: ");
MPPT51 0:d92f936cf10d 241 // printf(errorStatus);
MPPT51 0:d92f936cf10d 242 if (alertInterruptFlag == false && errorStatus == 0) {
MPPT51 0:d92f936cf10d 243 return 0;
MPPT51 0:d92f936cf10d 244 } else {
MPPT51 0:d92f936cf10d 245
MPPT51 0:d92f936cf10d 246 regSYS_STAT_t sys_stat;
MPPT51 0:d92f936cf10d 247 sys_stat.regByte = readRegister(SYS_STAT);
MPPT51 0:d92f936cf10d 248
MPPT51 0:d92f936cf10d 249 // first check, if only a new CC reading is available
MPPT51 0:d92f936cf10d 250 if (sys_stat.bits.CC_READY == 1) {
MPPT51 0:d92f936cf10d 251 //printf("Interrupt: CC ready");
MPPT51 0:d92f936cf10d 252 updateCurrent(); // automatically clears CC ready flag
MPPT51 0:d92f936cf10d 253 }
MPPT51 0:d92f936cf10d 254
MPPT51 0:d92f936cf10d 255 // Serious error occured
MPPT51 0:d92f936cf10d 256 if (sys_stat.regByte & 0b00111111)
MPPT51 0:d92f936cf10d 257 {
MPPT51 0:d92f936cf10d 258 if (alertInterruptFlag == true) {
MPPT51 0:d92f936cf10d 259 secSinceErrorCounter = 0;
MPPT51 0:d92f936cf10d 260 }
MPPT51 0:d92f936cf10d 261 errorStatus = sys_stat.regByte;
MPPT51 0:d92f936cf10d 262
MPPT51 0:d92f936cf10d 263 unsigned int secSinceInterrupt = (_timer.read_ms() - interruptTimestamp) / 1000;
MPPT51 0:d92f936cf10d 264
MPPT51 0:d92f936cf10d 265 // check for overrun of _timer.read_ms() or very slow running program
MPPT51 0:d92f936cf10d 266 if (abs((long)(secSinceInterrupt - secSinceErrorCounter)) > 2) {
MPPT51 0:d92f936cf10d 267 secSinceErrorCounter = secSinceInterrupt;
MPPT51 0:d92f936cf10d 268 }
MPPT51 0:d92f936cf10d 269
MPPT51 0:d92f936cf10d 270 // called only once per second
MPPT51 0:d92f936cf10d 271 if (secSinceInterrupt >= secSinceErrorCounter)
MPPT51 0:d92f936cf10d 272 {
MPPT51 0:d92f936cf10d 273 if (sys_stat.regByte & 0b00100000) { // XR error
MPPT51 0:d92f936cf10d 274 // datasheet recommendation: try to clear after waiting a few seconds
MPPT51 0:d92f936cf10d 275 if (secSinceErrorCounter % 3 == 0) {
MPPT51 0:d92f936cf10d 276 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 277 printf("Attempting to clear XR error");
MPPT51 0:d92f936cf10d 278 #endif
MPPT51 0:d92f936cf10d 279 writeRegister(SYS_STAT, 0b00100000);
MPPT51 0:d92f936cf10d 280 enableCharging();
MPPT51 0:d92f936cf10d 281 enableDischarging();
MPPT51 0:d92f936cf10d 282 }
MPPT51 0:d92f936cf10d 283 }
MPPT51 0:d92f936cf10d 284 if (sys_stat.regByte & 0b00010000) { // Alert error
MPPT51 0:d92f936cf10d 285 if (secSinceErrorCounter % 10 == 0) {
MPPT51 0:d92f936cf10d 286 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 287 printf("Attempting to clear Alert error");
MPPT51 0:d92f936cf10d 288 #endif
MPPT51 0:d92f936cf10d 289 writeRegister(SYS_STAT, 0b00010000);
MPPT51 0:d92f936cf10d 290 enableCharging();
MPPT51 0:d92f936cf10d 291 enableDischarging();
MPPT51 0:d92f936cf10d 292 }
MPPT51 0:d92f936cf10d 293 }
MPPT51 0:d92f936cf10d 294 if (sys_stat.regByte & 0b00001000) { // UV error
MPPT51 0:d92f936cf10d 295 updateVoltages();
MPPT51 0:d92f936cf10d 296 if (cellVoltages[idCellMinVoltage] > minCellVoltage) {
MPPT51 0:d92f936cf10d 297 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 298 printf("Attempting to clear UV error");
MPPT51 0:d92f936cf10d 299 #endif
MPPT51 0:d92f936cf10d 300 writeRegister(SYS_STAT, 0b00001000);
MPPT51 0:d92f936cf10d 301 enableDischarging();
MPPT51 0:d92f936cf10d 302 }
MPPT51 0:d92f936cf10d 303 }
MPPT51 0:d92f936cf10d 304 if (sys_stat.regByte & 0b00000100) { // OV error
MPPT51 0:d92f936cf10d 305 updateVoltages();
MPPT51 0:d92f936cf10d 306 if (cellVoltages[idCellMaxVoltage] < maxCellVoltage) {
MPPT51 0:d92f936cf10d 307 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 308 printf("Attempting to clear OV error");
MPPT51 0:d92f936cf10d 309 #endif
MPPT51 0:d92f936cf10d 310 writeRegister(SYS_STAT, 0b00000100);
MPPT51 0:d92f936cf10d 311 enableCharging();
MPPT51 0:d92f936cf10d 312 }
MPPT51 0:d92f936cf10d 313 }
MPPT51 0:d92f936cf10d 314 if (sys_stat.regByte & 0b00000010) { // SCD
MPPT51 0:d92f936cf10d 315 if (secSinceErrorCounter % 60 == 0) {
MPPT51 0:d92f936cf10d 316 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 317 printf("Attempting to clear SCD error");
MPPT51 0:d92f936cf10d 318 #endif
MPPT51 0:d92f936cf10d 319 writeRegister(SYS_STAT, 0b00000010);
MPPT51 0:d92f936cf10d 320 enableDischarging();
MPPT51 0:d92f936cf10d 321 }
MPPT51 0:d92f936cf10d 322 }
MPPT51 0:d92f936cf10d 323 if (sys_stat.regByte & 0b00000001) { // OCD
MPPT51 0:d92f936cf10d 324 if (secSinceErrorCounter % 60 == 0) {
MPPT51 0:d92f936cf10d 325 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 326 printf("Attempting to clear OCD error");
MPPT51 0:d92f936cf10d 327 #endif
MPPT51 0:d92f936cf10d 328 writeRegister(SYS_STAT, 0b00000001);
MPPT51 0:d92f936cf10d 329 enableDischarging();
MPPT51 0:d92f936cf10d 330 }
MPPT51 0:d92f936cf10d 331 }
MPPT51 0:d92f936cf10d 332 secSinceErrorCounter++;
MPPT51 0:d92f936cf10d 333 }
MPPT51 0:d92f936cf10d 334 }
MPPT51 0:d92f936cf10d 335 else {
MPPT51 0:d92f936cf10d 336 errorStatus = 0;
MPPT51 0:d92f936cf10d 337 }
MPPT51 0:d92f936cf10d 338
MPPT51 0:d92f936cf10d 339 return errorStatus;
MPPT51 0:d92f936cf10d 340 }
MPPT51 0:d92f936cf10d 341 }
MPPT51 0:d92f936cf10d 342
MPPT51 0:d92f936cf10d 343 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 344 // checks if temperatures are within the limits, otherwise disables CHG/DSG FET
MPPT51 0:d92f936cf10d 345
MPPT51 0:d92f936cf10d 346 void bq769x0::checkCellTemp()
MPPT51 0:d92f936cf10d 347 {
MPPT51 0:d92f936cf10d 348 int numberOfThermistors = numberOfCells/5;
MPPT51 0:d92f936cf10d 349 bool cellTempChargeError = 0;
MPPT51 0:d92f936cf10d 350 bool cellTempDischargeError = 0;
MPPT51 0:d92f936cf10d 351
MPPT51 0:d92f936cf10d 352 for (int thermistor = 0; thermistor < numberOfThermistors; thermistor++) {
MPPT51 0:d92f936cf10d 353 cellTempChargeError |=
MPPT51 0:d92f936cf10d 354 temperatures[thermistor] > maxCellTempCharge - cellTempChargeErrorFlag ? cellTempHysteresis : 0 ||
MPPT51 0:d92f936cf10d 355 temperatures[thermistor] < minCellTempCharge + cellTempChargeErrorFlag ? cellTempHysteresis : 0;
MPPT51 0:d92f936cf10d 356
MPPT51 0:d92f936cf10d 357 cellTempDischargeError |=
MPPT51 0:d92f936cf10d 358 temperatures[thermistor] > maxCellTempDischarge - cellTempDischargeErrorFlag ? cellTempHysteresis : 0 ||
MPPT51 0:d92f936cf10d 359 temperatures[thermistor] < minCellTempDischarge + cellTempDischargeErrorFlag ? cellTempHysteresis : 0;
MPPT51 0:d92f936cf10d 360 }
MPPT51 0:d92f936cf10d 361
MPPT51 0:d92f936cf10d 362 if (cellTempChargeErrorFlag != cellTempChargeError) {
MPPT51 0:d92f936cf10d 363 cellTempChargeErrorFlag = cellTempChargeError;
MPPT51 0:d92f936cf10d 364 if (cellTempChargeError) {
MPPT51 0:d92f936cf10d 365 disableCharging();
MPPT51 0:d92f936cf10d 366 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 367 printf("Temperature error (CHG)");
MPPT51 0:d92f936cf10d 368 #endif
MPPT51 0:d92f936cf10d 369 }
MPPT51 0:d92f936cf10d 370 else {
MPPT51 0:d92f936cf10d 371 enableCharging();
MPPT51 0:d92f936cf10d 372 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 373 printf("Clearing temperature error (CHG)");
MPPT51 0:d92f936cf10d 374 #endif
MPPT51 0:d92f936cf10d 375 }
MPPT51 0:d92f936cf10d 376 }
MPPT51 0:d92f936cf10d 377
MPPT51 0:d92f936cf10d 378 if (cellTempDischargeErrorFlag != cellTempDischargeError) {
MPPT51 0:d92f936cf10d 379 cellTempDischargeErrorFlag = cellTempDischargeError;
MPPT51 0:d92f936cf10d 380 if (cellTempDischargeError) {
MPPT51 0:d92f936cf10d 381 disableDischarging();
MPPT51 0:d92f936cf10d 382 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 383 printf("Temperature error (DSG)");
MPPT51 0:d92f936cf10d 384 #endif
MPPT51 0:d92f936cf10d 385 }
MPPT51 0:d92f936cf10d 386 else {
MPPT51 0:d92f936cf10d 387 enableDischarging();
MPPT51 0:d92f936cf10d 388 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 389 printf("Clearing temperature error (DSG)");
MPPT51 0:d92f936cf10d 390 #endif
MPPT51 0:d92f936cf10d 391 }
MPPT51 0:d92f936cf10d 392 }
MPPT51 0:d92f936cf10d 393 }
MPPT51 0:d92f936cf10d 394
MPPT51 0:d92f936cf10d 395 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 396 // should be called at least once every 250 ms to get correct coulomb counting
MPPT51 0:d92f936cf10d 397
MPPT51 0:d92f936cf10d 398 void bq769x0::update()
MPPT51 0:d92f936cf10d 399 {
MPPT51 0:d92f936cf10d 400 //updateCurrent(); // will only read new current value if alert was triggered
MPPT51 0:d92f936cf10d 401 updateVoltages();
MPPT51 0:d92f936cf10d 402 //updateTemperatures();
MPPT51 0:d92f936cf10d 403 //updateBalancingSwitches();
MPPT51 0:d92f936cf10d 404 //checkCellTemp();
MPPT51 0:d92f936cf10d 405 }
MPPT51 0:d92f936cf10d 406 void bq769x0::update1(){
MPPT51 0:d92f936cf10d 407 updateVoltages1();
MPPT51 0:d92f936cf10d 408 }
MPPT51 0:d92f936cf10d 409 void bq769x0::update2(){
MPPT51 0:d92f936cf10d 410 updateVoltages2();
MPPT51 0:d92f936cf10d 411 }
MPPT51 0:d92f936cf10d 412 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 413 // puts BMS IC into SHIP mode (i.e. switched off)
MPPT51 0:d92f936cf10d 414
MPPT51 0:d92f936cf10d 415 void bq769x0::shutdown()
MPPT51 0:d92f936cf10d 416 {
MPPT51 0:d92f936cf10d 417 writeRegister(SYS_CTRL1, 0x0);
MPPT51 0:d92f936cf10d 418 writeRegister(SYS_CTRL1, 0x1);
MPPT51 0:d92f936cf10d 419 writeRegister(SYS_CTRL1, 0x2);
MPPT51 0:d92f936cf10d 420 }
MPPT51 0:d92f936cf10d 421
MPPT51 0:d92f936cf10d 422 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 423
MPPT51 0:d92f936cf10d 424 bool bq769x0::enableCharging()
MPPT51 0:d92f936cf10d 425 {
MPPT51 0:d92f936cf10d 426 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 427 printf("checkStatus() = %d\n", checkStatus());
MPPT51 0:d92f936cf10d 428 printf("Umax = %d\n", cellVoltages[idCellMaxVoltage]);
MPPT51 0:d92f936cf10d 429 printf("temperatures[0] = %d\n", temperatures[0]);
MPPT51 0:d92f936cf10d 430 #endif
MPPT51 0:d92f936cf10d 431
MPPT51 0:d92f936cf10d 432 int numberOfThermistors = numberOfCells/5;
MPPT51 0:d92f936cf10d 433 bool cellTempChargeError = 0;
MPPT51 0:d92f936cf10d 434
MPPT51 0:d92f936cf10d 435 for (int thermistor = 0; thermistor < numberOfThermistors; thermistor++) {
MPPT51 0:d92f936cf10d 436 cellTempChargeError |=
MPPT51 0:d92f936cf10d 437 temperatures[thermistor] > maxCellTempCharge ||
MPPT51 0:d92f936cf10d 438 temperatures[thermistor] < minCellTempCharge;
MPPT51 0:d92f936cf10d 439 }
MPPT51 0:d92f936cf10d 440
MPPT51 0:d92f936cf10d 441 if (checkStatus() == 0 &&
MPPT51 0:d92f936cf10d 442 cellVoltages[idCellMaxVoltage] < maxCellVoltage &&
MPPT51 0:d92f936cf10d 443 cellTempChargeError == 0)
MPPT51 0:d92f936cf10d 444 {
MPPT51 0:d92f936cf10d 445 int sys_ctrl2;
MPPT51 0:d92f936cf10d 446 sys_ctrl2 = readRegister(SYS_CTRL2);
MPPT51 0:d92f936cf10d 447 writeRegister(SYS_CTRL2, sys_ctrl2 | 0b00000001); // switch CHG on
MPPT51 0:d92f936cf10d 448 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 449 printf("Enabling CHG FET\n");
MPPT51 0:d92f936cf10d 450 #endif
MPPT51 0:d92f936cf10d 451 return true;
MPPT51 0:d92f936cf10d 452 }
MPPT51 0:d92f936cf10d 453 else {
MPPT51 0:d92f936cf10d 454 return false;
MPPT51 0:d92f936cf10d 455 }
MPPT51 0:d92f936cf10d 456 }
MPPT51 0:d92f936cf10d 457
MPPT51 0:d92f936cf10d 458 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 459
MPPT51 0:d92f936cf10d 460 void bq769x0::disableCharging()
MPPT51 0:d92f936cf10d 461 {
MPPT51 0:d92f936cf10d 462 int sys_ctrl2;
MPPT51 0:d92f936cf10d 463 sys_ctrl2 = readRegister(SYS_CTRL2);
MPPT51 0:d92f936cf10d 464 writeRegister(SYS_CTRL2, sys_ctrl2 & ~0b00000001); // switch CHG off
MPPT51 0:d92f936cf10d 465 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 466 printf("Disabling CHG FET\n");
MPPT51 0:d92f936cf10d 467 #endif
MPPT51 0:d92f936cf10d 468 }
MPPT51 0:d92f936cf10d 469
MPPT51 0:d92f936cf10d 470 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 471
MPPT51 0:d92f936cf10d 472 bool bq769x0::enableDischarging()
MPPT51 0:d92f936cf10d 473 {
MPPT51 0:d92f936cf10d 474 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 475 printf("checkStatus() = %d\n", checkStatus());
MPPT51 0:d92f936cf10d 476 printf("Umin = %d\n", cellVoltages[idCellMinVoltage]);
MPPT51 0:d92f936cf10d 477 printf("temperatures[0] = %d\n", temperatures[0]);
MPPT51 0:d92f936cf10d 478 #endif
MPPT51 0:d92f936cf10d 479
MPPT51 0:d92f936cf10d 480 int numberOfThermistors = numberOfCells/5;
MPPT51 0:d92f936cf10d 481 bool cellTempDischargeError = 0;
MPPT51 0:d92f936cf10d 482
MPPT51 0:d92f936cf10d 483 for (int thermistor = 0; thermistor < numberOfThermistors; thermistor++) {
MPPT51 0:d92f936cf10d 484 cellTempDischargeError |=
MPPT51 0:d92f936cf10d 485 temperatures[thermistor] > maxCellTempDischarge ||
MPPT51 0:d92f936cf10d 486 temperatures[thermistor] < minCellTempDischarge;
MPPT51 0:d92f936cf10d 487 }
MPPT51 0:d92f936cf10d 488
MPPT51 0:d92f936cf10d 489 if (checkStatus() == 0 &&
MPPT51 0:d92f936cf10d 490 cellVoltages[idCellMinVoltage] > minCellVoltage &&
MPPT51 0:d92f936cf10d 491 cellTempDischargeError == 0)
MPPT51 0:d92f936cf10d 492 {
MPPT51 0:d92f936cf10d 493 int sys_ctrl2;
MPPT51 0:d92f936cf10d 494 sys_ctrl2 = readRegister(SYS_CTRL2);
MPPT51 0:d92f936cf10d 495 writeRegister(SYS_CTRL2, sys_ctrl2 | 0b00000010); // switch DSG on
MPPT51 0:d92f936cf10d 496 return true;
MPPT51 0:d92f936cf10d 497 }
MPPT51 0:d92f936cf10d 498 else {
MPPT51 0:d92f936cf10d 499 return false;
MPPT51 0:d92f936cf10d 500 }
MPPT51 0:d92f936cf10d 501 }
MPPT51 0:d92f936cf10d 502
MPPT51 0:d92f936cf10d 503 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 504
MPPT51 0:d92f936cf10d 505 void bq769x0::disableDischarging()
MPPT51 0:d92f936cf10d 506 {
MPPT51 0:d92f936cf10d 507 int sys_ctrl2;
MPPT51 0:d92f936cf10d 508 sys_ctrl2 = readRegister(SYS_CTRL2);
MPPT51 0:d92f936cf10d 509 writeRegister(SYS_CTRL2, sys_ctrl2 & ~0b00000010); // switch DSG off
MPPT51 0:d92f936cf10d 510 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 511 printf("Disabling DISCHG FET\n");
MPPT51 0:d92f936cf10d 512 #endif
MPPT51 0:d92f936cf10d 513 }
MPPT51 0:d92f936cf10d 514
MPPT51 0:d92f936cf10d 515 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 516
MPPT51 0:d92f936cf10d 517 void bq769x0::enableAutoBalancing(void)
MPPT51 0:d92f936cf10d 518 {
MPPT51 0:d92f936cf10d 519 autoBalancingEnabled = true;
MPPT51 0:d92f936cf10d 520 }
MPPT51 0:d92f936cf10d 521
MPPT51 0:d92f936cf10d 522
MPPT51 0:d92f936cf10d 523 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 524
MPPT51 0:d92f936cf10d 525 void bq769x0::setBalancingThresholds(int idleTime_min, int absVoltage_mV, int voltageDifference_mV)
MPPT51 0:d92f936cf10d 526 {
MPPT51 0:d92f936cf10d 527 balancingMinIdleTime_s = idleTime_min * 60;
MPPT51 0:d92f936cf10d 528 balancingMinCellVoltage_mV = absVoltage_mV;
MPPT51 0:d92f936cf10d 529 balancingMaxVoltageDifference_mV = voltageDifference_mV;
MPPT51 0:d92f936cf10d 530 }
MPPT51 0:d92f936cf10d 531
MPPT51 0:d92f936cf10d 532 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 533 // sets balancing registers if balancing is allowed
MPPT51 0:d92f936cf10d 534 // (sufficient idle time + voltage)
MPPT51 0:d92f936cf10d 535
MPPT51 0:d92f936cf10d 536 void bq769x0::updateBalancingSwitches(void)
MPPT51 0:d92f936cf10d 537 {
MPPT51 0:d92f936cf10d 538 long idleSeconds = (_timer.read_ms() - idleTimestamp) / 1000;
MPPT51 0:d92f936cf10d 539 int numberOfSections = numberOfCells/5;
MPPT51 0:d92f936cf10d 540
MPPT51 0:d92f936cf10d 541 // check for _timer.read_ms() overflow
MPPT51 0:d92f936cf10d 542 if (idleSeconds < 0) {
MPPT51 0:d92f936cf10d 543 idleTimestamp = 0;
MPPT51 0:d92f936cf10d 544 idleSeconds = _timer.read_ms() / 1000;
MPPT51 0:d92f936cf10d 545 }
MPPT51 0:d92f936cf10d 546
MPPT51 0:d92f936cf10d 547 // check if balancing allowed
MPPT51 0:d92f936cf10d 548 if (checkStatus() == 0 &&
MPPT51 0:d92f936cf10d 549 idleSeconds >= balancingMinIdleTime_s &&
MPPT51 0:d92f936cf10d 550 cellVoltages[idCellMaxVoltage] > balancingMinCellVoltage_mV &&
MPPT51 0:d92f936cf10d 551 (cellVoltages[idCellMaxVoltage] - cellVoltages[idCellMinVoltage]) > balancingMaxVoltageDifference_mV)
MPPT51 0:d92f936cf10d 552 {
MPPT51 0:d92f936cf10d 553 //printf("Balancing enabled!");
MPPT51 0:d92f936cf10d 554 balancingStatus = 0; // current status will be set in following loop
MPPT51 0:d92f936cf10d 555
MPPT51 0:d92f936cf10d 556 //regCELLBAL_t cellbal;
MPPT51 0:d92f936cf10d 557 int balancingFlags;
MPPT51 0:d92f936cf10d 558 int balancingFlagsTarget;
MPPT51 0:d92f936cf10d 559
MPPT51 0:d92f936cf10d 560 for (int section = 0; section < numberOfSections; section++)
MPPT51 0:d92f936cf10d 561 {
MPPT51 0:d92f936cf10d 562 // find cells which should be balanced and sort them by voltage descending
MPPT51 0:d92f936cf10d 563 int cellList[5];
MPPT51 0:d92f936cf10d 564 int cellCounter = 0;
MPPT51 0:d92f936cf10d 565 for (int i = 0; i < 5; i++)
MPPT51 0:d92f936cf10d 566 {
MPPT51 0:d92f936cf10d 567 if ((cellVoltages[section*5 + i] - cellVoltages[idCellMinVoltage]) > balancingMaxVoltageDifference_mV) {
MPPT51 0:d92f936cf10d 568 int j = cellCounter;
MPPT51 0:d92f936cf10d 569 while (j > 0 && cellVoltages[section*5 + cellList[j - 1]] < cellVoltages[section*5 + i])
MPPT51 0:d92f936cf10d 570 {
MPPT51 0:d92f936cf10d 571 cellList[j] = cellList[j - 1];
MPPT51 0:d92f936cf10d 572 j--;
MPPT51 0:d92f936cf10d 573 }
MPPT51 0:d92f936cf10d 574 cellList[j] = i;
MPPT51 0:d92f936cf10d 575 cellCounter++;
MPPT51 0:d92f936cf10d 576 }
MPPT51 0:d92f936cf10d 577 }
MPPT51 0:d92f936cf10d 578
MPPT51 0:d92f936cf10d 579 balancingFlags = 0;
MPPT51 0:d92f936cf10d 580 for (int i = 0; i < cellCounter; i++)
MPPT51 0:d92f936cf10d 581 {
MPPT51 0:d92f936cf10d 582 // try to enable balancing of current cell
MPPT51 0:d92f936cf10d 583 balancingFlagsTarget = balancingFlags | (1 << cellList[i]);
MPPT51 0:d92f936cf10d 584
MPPT51 0:d92f936cf10d 585 // check if attempting to balance adjacent cells
MPPT51 0:d92f936cf10d 586 bool adjacentCellCollision =
MPPT51 0:d92f936cf10d 587 ((balancingFlagsTarget << 1) & balancingFlags) ||
MPPT51 0:d92f936cf10d 588 ((balancingFlags << 1) & balancingFlagsTarget);
MPPT51 0:d92f936cf10d 589
MPPT51 0:d92f936cf10d 590 if (adjacentCellCollision == false) {
MPPT51 0:d92f936cf10d 591 balancingFlags = balancingFlagsTarget;
MPPT51 0:d92f936cf10d 592 }
MPPT51 0:d92f936cf10d 593 }
MPPT51 0:d92f936cf10d 594
MPPT51 0:d92f936cf10d 595 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 596 //printf("Setting CELLBAL%d register to: %s\n", section+1, byte2char(balancingFlags));
MPPT51 0:d92f936cf10d 597 #endif
MPPT51 0:d92f936cf10d 598
MPPT51 0:d92f936cf10d 599 balancingStatus |= balancingFlags << section*5;
MPPT51 0:d92f936cf10d 600
MPPT51 0:d92f936cf10d 601 // set balancing register for this section
MPPT51 0:d92f936cf10d 602 writeRegister(CELLBAL1+section, balancingFlags);
MPPT51 0:d92f936cf10d 603
MPPT51 0:d92f936cf10d 604 } // section loop
MPPT51 0:d92f936cf10d 605 }
MPPT51 0:d92f936cf10d 606 else if (balancingStatus > 0)
MPPT51 0:d92f936cf10d 607 {
MPPT51 0:d92f936cf10d 608 // clear all CELLBAL registers
MPPT51 0:d92f936cf10d 609 for (int section = 0; section < numberOfSections; section++)
MPPT51 0:d92f936cf10d 610 {
MPPT51 0:d92f936cf10d 611 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 612 printf("Clearing Register CELLBAL%d\n", section+1);
MPPT51 0:d92f936cf10d 613 #endif
MPPT51 0:d92f936cf10d 614
MPPT51 0:d92f936cf10d 615 writeRegister(CELLBAL1+section, 0x0);
MPPT51 0:d92f936cf10d 616 }
MPPT51 0:d92f936cf10d 617
MPPT51 0:d92f936cf10d 618 balancingStatus = 0;
MPPT51 0:d92f936cf10d 619 }
MPPT51 0:d92f936cf10d 620 }
MPPT51 0:d92f936cf10d 621
MPPT51 0:d92f936cf10d 622 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 623
MPPT51 0:d92f936cf10d 624 int bq769x0::getBalancingStatus()
MPPT51 0:d92f936cf10d 625 {
MPPT51 0:d92f936cf10d 626 return balancingStatus;
MPPT51 0:d92f936cf10d 627 }
MPPT51 0:d92f936cf10d 628
MPPT51 0:d92f936cf10d 629 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 630
MPPT51 0:d92f936cf10d 631 void bq769x0::setShuntResistorValue(float res_mOhm)
MPPT51 0:d92f936cf10d 632 {
MPPT51 0:d92f936cf10d 633 shuntResistorValue_mOhm = res_mOhm;
MPPT51 0:d92f936cf10d 634 }
MPPT51 0:d92f936cf10d 635
MPPT51 0:d92f936cf10d 636 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 637
MPPT51 0:d92f936cf10d 638 void bq769x0::setThermistorBetaValue(int beta_K)
MPPT51 0:d92f936cf10d 639 {
MPPT51 0:d92f936cf10d 640 thermistorBetaValue = beta_K;
MPPT51 0:d92f936cf10d 641 }
MPPT51 0:d92f936cf10d 642
MPPT51 0:d92f936cf10d 643 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 644
MPPT51 0:d92f936cf10d 645 void bq769x0::setBatteryCapacity(long capacity_mAh)
MPPT51 0:d92f936cf10d 646 {
MPPT51 0:d92f936cf10d 647 nominalCapacity = capacity_mAh * 3600;
MPPT51 0:d92f936cf10d 648 }
MPPT51 0:d92f936cf10d 649
MPPT51 0:d92f936cf10d 650 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 651
MPPT51 0:d92f936cf10d 652 void bq769x0::setOCV(int voltageVsSOC[NUM_OCV_POINTS])
MPPT51 0:d92f936cf10d 653 {
MPPT51 0:d92f936cf10d 654 OCV = voltageVsSOC;
MPPT51 0:d92f936cf10d 655 }
MPPT51 0:d92f936cf10d 656
MPPT51 0:d92f936cf10d 657 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 658
MPPT51 0:d92f936cf10d 659 float bq769x0::getSOC(void)
MPPT51 0:d92f936cf10d 660 {
MPPT51 0:d92f936cf10d 661 return (double) coulombCounter / nominalCapacity * 100;
MPPT51 0:d92f936cf10d 662 }
MPPT51 0:d92f936cf10d 663
MPPT51 0:d92f936cf10d 664 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 665 // SOC calculation based on average cell open circuit voltage
MPPT51 0:d92f936cf10d 666
MPPT51 0:d92f936cf10d 667 void bq769x0::resetSOC(int percent)
MPPT51 0:d92f936cf10d 668 {
MPPT51 0:d92f936cf10d 669 if (percent <= 100 && percent >= 0)
MPPT51 0:d92f936cf10d 670 {
MPPT51 0:d92f936cf10d 671 coulombCounter = nominalCapacity * (percent / 100.0);
MPPT51 0:d92f936cf10d 672 }
MPPT51 0:d92f936cf10d 673 else // reset based on OCV
MPPT51 0:d92f936cf10d 674 {
MPPT51 0:d92f936cf10d 675 printf("NumCells: %d, voltage: %d V\n", getNumberOfConnectedCells(), getBatteryVoltage());
MPPT51 0:d92f936cf10d 676 int voltage = getBatteryVoltage() / getNumberOfConnectedCells();
MPPT51 0:d92f936cf10d 677
MPPT51 0:d92f936cf10d 678 coulombCounter = 0; // initialize with totally depleted battery (0% SOC)
MPPT51 0:d92f936cf10d 679
MPPT51 0:d92f936cf10d 680 for (int i = 0; i < NUM_OCV_POINTS; i++)
MPPT51 0:d92f936cf10d 681 {
MPPT51 0:d92f936cf10d 682 if (OCV[i] <= voltage) {
MPPT51 0:d92f936cf10d 683 if (i == 0) {
MPPT51 0:d92f936cf10d 684 coulombCounter = nominalCapacity; // 100% full
MPPT51 0:d92f936cf10d 685 }
MPPT51 0:d92f936cf10d 686 else {
MPPT51 0:d92f936cf10d 687 // interpolate between OCV[i] and OCV[i-1]
MPPT51 0:d92f936cf10d 688 coulombCounter = (double) nominalCapacity / (NUM_OCV_POINTS - 1.0) *
MPPT51 0:d92f936cf10d 689 (NUM_OCV_POINTS - 1.0 - i + ((float)voltage - OCV[i])/(OCV[i-1] - OCV[i]));
MPPT51 0:d92f936cf10d 690 }
MPPT51 0:d92f936cf10d 691 return;
MPPT51 0:d92f936cf10d 692 }
MPPT51 0:d92f936cf10d 693 }
MPPT51 0:d92f936cf10d 694 }
MPPT51 0:d92f936cf10d 695 }
MPPT51 0:d92f936cf10d 696
MPPT51 0:d92f936cf10d 697 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 698
MPPT51 0:d92f936cf10d 699 void bq769x0::setTemperatureLimits(int minDischarge_degC, int maxDischarge_degC,
MPPT51 0:d92f936cf10d 700 int minCharge_degC, int maxCharge_degC, int hysteresis_degC)
MPPT51 0:d92f936cf10d 701 {
MPPT51 0:d92f936cf10d 702 // Temperature limits (°C/10)
MPPT51 0:d92f936cf10d 703 minCellTempDischarge = minDischarge_degC * 10;
MPPT51 0:d92f936cf10d 704 maxCellTempDischarge = maxDischarge_degC * 10;
MPPT51 0:d92f936cf10d 705 minCellTempCharge = minCharge_degC * 10;
MPPT51 0:d92f936cf10d 706 maxCellTempCharge = maxCharge_degC * 10;
MPPT51 0:d92f936cf10d 707 cellTempHysteresis = hysteresis_degC * 10;
MPPT51 0:d92f936cf10d 708 }
MPPT51 0:d92f936cf10d 709
MPPT51 0:d92f936cf10d 710 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 711
MPPT51 0:d92f936cf10d 712 void bq769x0::setIdleCurrentThreshold(int current_mA)
MPPT51 0:d92f936cf10d 713 {
MPPT51 0:d92f936cf10d 714 idleCurrentThreshold = current_mA;
MPPT51 0:d92f936cf10d 715 }
MPPT51 0:d92f936cf10d 716
MPPT51 0:d92f936cf10d 717 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 718
MPPT51 0:d92f936cf10d 719 long bq769x0::setShortCircuitProtection(long current_mA, int delay_us)
MPPT51 0:d92f936cf10d 720 {
MPPT51 0:d92f936cf10d 721 regPROTECT1_t protect1;
MPPT51 0:d92f936cf10d 722
MPPT51 0:d92f936cf10d 723 // only RSNS = 1 considered
MPPT51 0:d92f936cf10d 724 protect1.bits.RSNS = 1;
MPPT51 0:d92f936cf10d 725
MPPT51 0:d92f936cf10d 726 protect1.bits.SCD_THRESH = 0;
MPPT51 0:d92f936cf10d 727 for (int i = sizeof(SCD_threshold_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 728 if (current_mA * shuntResistorValue_mOhm / 1000 >= SCD_threshold_setting[i]) {
MPPT51 0:d92f936cf10d 729 protect1.bits.SCD_THRESH = i;
MPPT51 0:d92f936cf10d 730 break;
MPPT51 0:d92f936cf10d 731 }
MPPT51 0:d92f936cf10d 732 }
MPPT51 0:d92f936cf10d 733
MPPT51 0:d92f936cf10d 734 protect1.bits.SCD_DELAY = 0;
MPPT51 0:d92f936cf10d 735 for (int i = sizeof(SCD_delay_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 736 if (delay_us >= SCD_delay_setting[i]) {
MPPT51 0:d92f936cf10d 737 protect1.bits.SCD_DELAY = i;
MPPT51 0:d92f936cf10d 738 break;
MPPT51 0:d92f936cf10d 739 }
MPPT51 0:d92f936cf10d 740 }
MPPT51 0:d92f936cf10d 741
MPPT51 0:d92f936cf10d 742 writeRegister(PROTECT1, protect1.regByte);
MPPT51 0:d92f936cf10d 743
MPPT51 0:d92f936cf10d 744 // returns the actual current threshold value
MPPT51 0:d92f936cf10d 745 return (long)SCD_threshold_setting[protect1.bits.SCD_THRESH] * 1000 /
MPPT51 0:d92f936cf10d 746 shuntResistorValue_mOhm;
MPPT51 0:d92f936cf10d 747 }
MPPT51 0:d92f936cf10d 748
MPPT51 0:d92f936cf10d 749 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 750
MPPT51 0:d92f936cf10d 751 long bq769x0::setOvercurrentChargeProtection(long current_mA, int delay_ms)
MPPT51 0:d92f936cf10d 752 {
MPPT51 0:d92f936cf10d 753 // ToDo: Software protection for charge overcurrent
MPPT51 0:d92f936cf10d 754 return 0;
MPPT51 0:d92f936cf10d 755 }
MPPT51 0:d92f936cf10d 756
MPPT51 0:d92f936cf10d 757 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 758
MPPT51 0:d92f936cf10d 759 long bq769x0::setOvercurrentDischargeProtection(long current_mA, int delay_ms)
MPPT51 0:d92f936cf10d 760 {
MPPT51 0:d92f936cf10d 761 regPROTECT2_t protect2;
MPPT51 0:d92f936cf10d 762
MPPT51 0:d92f936cf10d 763 // Remark: RSNS must be set to 1 in PROTECT1 register
MPPT51 0:d92f936cf10d 764
MPPT51 0:d92f936cf10d 765 protect2.bits.OCD_THRESH = 0;
MPPT51 0:d92f936cf10d 766 for (int i = sizeof(OCD_threshold_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 767 if (current_mA * shuntResistorValue_mOhm / 1000 >= OCD_threshold_setting[i]) {
MPPT51 0:d92f936cf10d 768 protect2.bits.OCD_THRESH = i;
MPPT51 0:d92f936cf10d 769 break;
MPPT51 0:d92f936cf10d 770 }
MPPT51 0:d92f936cf10d 771 }
MPPT51 0:d92f936cf10d 772
MPPT51 0:d92f936cf10d 773 protect2.bits.OCD_DELAY = 0;
MPPT51 0:d92f936cf10d 774 for (int i = sizeof(OCD_delay_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 775 if (delay_ms >= OCD_delay_setting[i]) {
MPPT51 0:d92f936cf10d 776 protect2.bits.OCD_DELAY = i;
MPPT51 0:d92f936cf10d 777 break;
MPPT51 0:d92f936cf10d 778 }
MPPT51 0:d92f936cf10d 779 }
MPPT51 0:d92f936cf10d 780
MPPT51 0:d92f936cf10d 781 writeRegister(PROTECT2, protect2.regByte);
MPPT51 0:d92f936cf10d 782
MPPT51 0:d92f936cf10d 783 // returns the actual current threshold value
MPPT51 0:d92f936cf10d 784 return (long)OCD_threshold_setting[protect2.bits.OCD_THRESH] * 1000 /
MPPT51 0:d92f936cf10d 785 shuntResistorValue_mOhm;
MPPT51 0:d92f936cf10d 786 }
MPPT51 0:d92f936cf10d 787
MPPT51 0:d92f936cf10d 788
MPPT51 0:d92f936cf10d 789 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 790
MPPT51 0:d92f936cf10d 791 int bq769x0::setCellUndervoltageProtection(int voltage_mV, int delay_s)
MPPT51 0:d92f936cf10d 792 {
MPPT51 0:d92f936cf10d 793 regPROTECT3_t protect3;
MPPT51 0:d92f936cf10d 794 int uv_trip = 0;
MPPT51 0:d92f936cf10d 795
MPPT51 0:d92f936cf10d 796 minCellVoltage = voltage_mV;
MPPT51 0:d92f936cf10d 797
MPPT51 0:d92f936cf10d 798 protect3.regByte = readRegister(PROTECT3);
MPPT51 0:d92f936cf10d 799
MPPT51 0:d92f936cf10d 800 uv_trip = ((((long)voltage_mV - adcOffset) * 1000 / adcGain) >> 4) & 0x00FF;
MPPT51 0:d92f936cf10d 801 uv_trip += 1; // always round up for lower cell voltage
MPPT51 0:d92f936cf10d 802 writeRegister(UV_TRIP, uv_trip);
MPPT51 0:d92f936cf10d 803
MPPT51 0:d92f936cf10d 804 protect3.bits.UV_DELAY = 0;
MPPT51 0:d92f936cf10d 805 for (int i = sizeof(UV_delay_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 806 if (delay_s >= UV_delay_setting[i]) {
MPPT51 0:d92f936cf10d 807 protect3.bits.UV_DELAY = i;
MPPT51 0:d92f936cf10d 808 break;
MPPT51 0:d92f936cf10d 809 }
MPPT51 0:d92f936cf10d 810 }
MPPT51 0:d92f936cf10d 811
MPPT51 0:d92f936cf10d 812 writeRegister(PROTECT3, protect3.regByte);
MPPT51 0:d92f936cf10d 813
MPPT51 0:d92f936cf10d 814 // returns the actual current threshold value
MPPT51 0:d92f936cf10d 815 return ((long)1 << 12 | uv_trip << 4) * adcGain / 1000 + adcOffset;
MPPT51 0:d92f936cf10d 816 }
MPPT51 0:d92f936cf10d 817
MPPT51 0:d92f936cf10d 818 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 819
MPPT51 0:d92f936cf10d 820 int bq769x0::setCellOvervoltageProtection(int voltage_mV, int delay_s)
MPPT51 0:d92f936cf10d 821 {
MPPT51 0:d92f936cf10d 822 regPROTECT3_t protect3;
MPPT51 0:d92f936cf10d 823 int ov_trip = 0;
MPPT51 0:d92f936cf10d 824
MPPT51 0:d92f936cf10d 825 maxCellVoltage = voltage_mV;
MPPT51 0:d92f936cf10d 826
MPPT51 0:d92f936cf10d 827 protect3.regByte = readRegister(PROTECT3);
MPPT51 0:d92f936cf10d 828
MPPT51 0:d92f936cf10d 829 ov_trip = ((((long)voltage_mV - adcOffset) * 1000 / adcGain) >> 4) & 0x00FF;
MPPT51 0:d92f936cf10d 830 writeRegister(OV_TRIP, ov_trip);
MPPT51 0:d92f936cf10d 831
MPPT51 0:d92f936cf10d 832 protect3.bits.OV_DELAY = 0;
MPPT51 0:d92f936cf10d 833 for (int i = sizeof(OV_delay_setting)-1; i > 0; i--) {
MPPT51 0:d92f936cf10d 834 if (delay_s >= OV_delay_setting[i]) {
MPPT51 0:d92f936cf10d 835 protect3.bits.OV_DELAY = i;
MPPT51 0:d92f936cf10d 836 break;
MPPT51 0:d92f936cf10d 837 }
MPPT51 0:d92f936cf10d 838 }
MPPT51 0:d92f936cf10d 839
MPPT51 0:d92f936cf10d 840 writeRegister(PROTECT3, protect3.regByte);
MPPT51 0:d92f936cf10d 841
MPPT51 0:d92f936cf10d 842 // returns the actual current threshold value
MPPT51 0:d92f936cf10d 843 return ((long)1 << 13 | ov_trip << 4) * adcGain / 1000 + adcOffset;
MPPT51 0:d92f936cf10d 844 }
MPPT51 0:d92f936cf10d 845
MPPT51 0:d92f936cf10d 846
MPPT51 0:d92f936cf10d 847 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 848
MPPT51 0:d92f936cf10d 849 int bq769x0::getBatteryCurrent()
MPPT51 0:d92f936cf10d 850 {
MPPT51 0:d92f936cf10d 851 return batCurrent;
MPPT51 0:d92f936cf10d 852 }
MPPT51 0:d92f936cf10d 853
MPPT51 0:d92f936cf10d 854 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 855
MPPT51 0:d92f936cf10d 856 int bq769x0::getBatteryVoltage()
MPPT51 0:d92f936cf10d 857 {
MPPT51 0:d92f936cf10d 858 return batVoltage;
MPPT51 0:d92f936cf10d 859 }
MPPT51 0:d92f936cf10d 860
MPPT51 0:d92f936cf10d 861 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 862
MPPT51 0:d92f936cf10d 863 int bq769x0::getMaxCellVoltage()
MPPT51 0:d92f936cf10d 864 {
MPPT51 0:d92f936cf10d 865 return cellVoltages[idCellMaxVoltage];
MPPT51 0:d92f936cf10d 866 }
MPPT51 0:d92f936cf10d 867
MPPT51 0:d92f936cf10d 868 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 869
MPPT51 0:d92f936cf10d 870 int bq769x0::getMinCellVoltage()
MPPT51 0:d92f936cf10d 871 {
MPPT51 0:d92f936cf10d 872 return cellVoltages[idCellMinVoltage];
MPPT51 0:d92f936cf10d 873 }
MPPT51 0:d92f936cf10d 874
MPPT51 0:d92f936cf10d 875 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 876
MPPT51 0:d92f936cf10d 877 int bq769x0::getCellVoltage(int idCell)
MPPT51 0:d92f936cf10d 878 {
MPPT51 0:d92f936cf10d 879 return cellVoltages[idCell-1];
MPPT51 0:d92f936cf10d 880 }
MPPT51 0:d92f936cf10d 881
MPPT51 0:d92f936cf10d 882 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 883
MPPT51 0:d92f936cf10d 884 int bq769x0::getNumberOfCells(void)
MPPT51 0:d92f936cf10d 885 {
MPPT51 0:d92f936cf10d 886 return numberOfCells;
MPPT51 0:d92f936cf10d 887 }
MPPT51 0:d92f936cf10d 888
MPPT51 0:d92f936cf10d 889 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 890
MPPT51 0:d92f936cf10d 891 int bq769x0::getNumberOfConnectedCells(void)
MPPT51 0:d92f936cf10d 892 {
MPPT51 0:d92f936cf10d 893 return connectedCells;
MPPT51 0:d92f936cf10d 894 }
MPPT51 0:d92f936cf10d 895
MPPT51 0:d92f936cf10d 896 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 897
MPPT51 0:d92f936cf10d 898 float bq769x0::getTemperatureDegC(int channel)
MPPT51 0:d92f936cf10d 899 {
MPPT51 0:d92f936cf10d 900 if (channel >= 1 && channel <= 3) {
MPPT51 0:d92f936cf10d 901 return (float)temperatures[channel-1] / 10.0;
MPPT51 0:d92f936cf10d 902 }
MPPT51 0:d92f936cf10d 903 else {
MPPT51 0:d92f936cf10d 904 return -273.15; // Error: Return absolute minimum temperature
MPPT51 0:d92f936cf10d 905 }
MPPT51 0:d92f936cf10d 906 }
MPPT51 0:d92f936cf10d 907
MPPT51 0:d92f936cf10d 908 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 909
MPPT51 0:d92f936cf10d 910 float bq769x0::getTemperatureDegF(int channel)
MPPT51 0:d92f936cf10d 911 {
MPPT51 0:d92f936cf10d 912 return getTemperatureDegC(channel) * 1.8 + 32;
MPPT51 0:d92f936cf10d 913 }
MPPT51 0:d92f936cf10d 914
MPPT51 0:d92f936cf10d 915
MPPT51 0:d92f936cf10d 916 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 917
MPPT51 0:d92f936cf10d 918 void bq769x0::updateTemperatures()
MPPT51 0:d92f936cf10d 919 {
MPPT51 0:d92f936cf10d 920 float tmp = 0;
MPPT51 0:d92f936cf10d 921 int adcVal = 0;
MPPT51 0:d92f936cf10d 922 int vtsx = 0;
MPPT51 0:d92f936cf10d 923 unsigned long rts = 0;
MPPT51 0:d92f936cf10d 924
MPPT51 0:d92f936cf10d 925 // calculate R_thermistor according to bq769x0 datasheet
MPPT51 0:d92f936cf10d 926 adcVal = (readRegister(TS1_HI_BYTE) & 0b00111111) << 8 | readRegister(TS1_LO_BYTE);
MPPT51 0:d92f936cf10d 927 vtsx = adcVal * 0.382; // mV
MPPT51 0:d92f936cf10d 928 rts = 10000.0 * vtsx / (3300.0 - vtsx); // Ohm
MPPT51 0:d92f936cf10d 929
MPPT51 0:d92f936cf10d 930 // Temperature calculation using Beta equation
MPPT51 0:d92f936cf10d 931 // - According to bq769x0 datasheet, only 10k thermistors should be used
MPPT51 0:d92f936cf10d 932 // - 25°C reference temperature for Beta equation assumed
MPPT51 0:d92f936cf10d 933 tmp = 1.0/(1.0/(273.15+25) + 1.0/thermistorBetaValue*log(rts/10000.0)); // K
MPPT51 0:d92f936cf10d 934 temperatures[0] = (tmp - 273.15) * 10.0;
MPPT51 0:d92f936cf10d 935
MPPT51 0:d92f936cf10d 936 if (type == bq76930 || type == bq76940) {
MPPT51 0:d92f936cf10d 937 adcVal = (readRegister(TS2_HI_BYTE) & 0b00111111) << 8 | readRegister(TS2_LO_BYTE);
MPPT51 0:d92f936cf10d 938 vtsx = adcVal * 0.382; // mV
MPPT51 0:d92f936cf10d 939 rts = 10000.0 * vtsx / (3300.0 - vtsx); // Ohm
MPPT51 0:d92f936cf10d 940 tmp = 1.0/(1.0/(273.15+25) + 1.0/thermistorBetaValue*log(rts/10000.0)); // K
MPPT51 0:d92f936cf10d 941 temperatures[1] = (tmp - 273.15) * 10.0;
MPPT51 0:d92f936cf10d 942 }
MPPT51 0:d92f936cf10d 943
MPPT51 0:d92f936cf10d 944 if (type == bq76940) {
MPPT51 0:d92f936cf10d 945 adcVal = (readRegister(TS3_HI_BYTE) & 0b00111111) << 8 | readRegister(TS3_LO_BYTE);
MPPT51 0:d92f936cf10d 946 vtsx = adcVal * 0.382; // mV
MPPT51 0:d92f936cf10d 947 rts = 10000.0 * vtsx / (3300.0 - vtsx); // Ohm
MPPT51 0:d92f936cf10d 948 tmp = 1.0/(1.0/(273.15+25) + 1.0/thermistorBetaValue*log(rts/10000.0)); // K
MPPT51 0:d92f936cf10d 949 temperatures[2] = (tmp - 273.15) * 10.0;
MPPT51 0:d92f936cf10d 950 }
MPPT51 0:d92f936cf10d 951 }
MPPT51 0:d92f936cf10d 952
MPPT51 0:d92f936cf10d 953
MPPT51 0:d92f936cf10d 954 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 955
MPPT51 0:d92f936cf10d 956 void bq769x0::updateCurrent()
MPPT51 0:d92f936cf10d 957 {
MPPT51 0:d92f936cf10d 958 int adcVal = 0;
MPPT51 0:d92f936cf10d 959 regSYS_STAT_t sys_stat;
MPPT51 0:d92f936cf10d 960 sys_stat.regByte = readRegister(SYS_STAT);
MPPT51 0:d92f936cf10d 961
MPPT51 0:d92f936cf10d 962 // check if new current reading available
MPPT51 0:d92f936cf10d 963 if (sys_stat.bits.CC_READY == 1)
MPPT51 0:d92f936cf10d 964 {
MPPT51 0:d92f936cf10d 965 //printf("reading CC register...\n");
MPPT51 0:d92f936cf10d 966 adcVal = (readRegister(CC_HI_BYTE) << 8) | readRegister(CC_LO_BYTE);
MPPT51 0:d92f936cf10d 967 batCurrent = (int16_t) adcVal * 8.44 / shuntResistorValue_mOhm; // mA
MPPT51 0:d92f936cf10d 968
MPPT51 0:d92f936cf10d 969 coulombCounter += batCurrent / 4; // is read every 250 ms
MPPT51 0:d92f936cf10d 970
MPPT51 0:d92f936cf10d 971 // reduce resolution for actual current value
MPPT51 0:d92f936cf10d 972 if (batCurrent > -10 && batCurrent < 10) {
MPPT51 0:d92f936cf10d 973 batCurrent = 0;
MPPT51 0:d92f936cf10d 974 }
MPPT51 0:d92f936cf10d 975
MPPT51 0:d92f936cf10d 976 // reset idleTimestamp
MPPT51 0:d92f936cf10d 977 if (abs(batCurrent) > idleCurrentThreshold) {
MPPT51 0:d92f936cf10d 978 idleTimestamp = _timer.read_ms();
MPPT51 0:d92f936cf10d 979 }
MPPT51 0:d92f936cf10d 980
MPPT51 0:d92f936cf10d 981 // no error occured which caused alert
MPPT51 0:d92f936cf10d 982 if (!(sys_stat.regByte & 0b00111111)) {
MPPT51 0:d92f936cf10d 983 alertInterruptFlag = false;
MPPT51 0:d92f936cf10d 984 }
MPPT51 0:d92f936cf10d 985
MPPT51 0:d92f936cf10d 986 writeRegister(SYS_STAT, 0b10000000); // Clear CC ready flag
MPPT51 0:d92f936cf10d 987 }
MPPT51 0:d92f936cf10d 988 }
MPPT51 0:d92f936cf10d 989
MPPT51 0:d92f936cf10d 990 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 991 // reads all cell voltages to array cellVoltages[NUM_CELLS] and updates batVoltage
MPPT51 0:d92f936cf10d 992
MPPT51 0:d92f936cf10d 993 void bq769x0::updateVoltages()
MPPT51 0:d92f936cf10d 994 {
MPPT51 0:d92f936cf10d 995 long adcVal = 0;
MPPT51 0:d92f936cf10d 996 char buf[4];
MPPT51 0:d92f936cf10d 997 int connectedCellsTemp = 0;
MPPT51 0:d92f936cf10d 998
MPPT51 0:d92f936cf10d 999 uint8_t crc;
MPPT51 0:d92f936cf10d 1000
MPPT51 0:d92f936cf10d 1001 // read cell voltages
MPPT51 0:d92f936cf10d 1002 buf[0] = (char) VC1_HI_BYTE;
MPPT51 0:d92f936cf10d 1003 _i2c.write(I2CAddress << 1, buf, 1);
MPPT51 0:d92f936cf10d 1004 printf("Tx:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1005
MPPT51 0:d92f936cf10d 1006 idCellMaxVoltage = 0;
MPPT51 0:d92f936cf10d 1007 idCellMinVoltage = 0;
MPPT51 0:d92f936cf10d 1008 for (int i = 0; i < numberOfCells; i++)
MPPT51 0:d92f936cf10d 1009 {
MPPT51 0:d92f936cf10d 1010 if (crcEnabled == true) {
MPPT51 0:d92f936cf10d 1011 _i2c.read(I2CAddress << 1, buf, 4);
MPPT51 0:d92f936cf10d 1012 adcVal = (buf[0] & 0b00111111) << 8 | buf[2];
MPPT51 0:d92f936cf10d 1013
MPPT51 0:d92f936cf10d 1014 // CRC of first bytes includes slave address (including R/W bit) and data
MPPT51 0:d92f936cf10d 1015 crc = _crc8_ccitt_update(0, (I2CAddress << 1) | 1);
MPPT51 0:d92f936cf10d 1016 crc = _crc8_ccitt_update(crc, buf[0]);
MPPT51 0:d92f936cf10d 1017 if (crc != buf[1]) return; // don't save corrupted value
MPPT51 0:d92f936cf10d 1018
MPPT51 0:d92f936cf10d 1019 // CRC of subsequent bytes contain only data
MPPT51 0:d92f936cf10d 1020 crc = _crc8_ccitt_update(0, buf[2]);
MPPT51 0:d92f936cf10d 1021 if (crc != buf[3]) return; // don't save corrupted value
MPPT51 0:d92f936cf10d 1022 }
MPPT51 0:d92f936cf10d 1023 else {
MPPT51 0:d92f936cf10d 1024 //printf("XX:%d\n\r", i);
MPPT51 0:d92f936cf10d 1025 _i2c.read(I2CAddress << 1, buf, 2);
MPPT51 0:d92f936cf10d 1026 adcVal = (buf[0] & 0b00111111) << 8 | buf[1];
MPPT51 0:d92f936cf10d 1027 printf("Rx:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1028 //printf("%d, %d, %d, %d\n\r", cellVoltages[i], adcVal, adcGain, adcOffset);
MPPT51 0:d92f936cf10d 1029 }
MPPT51 0:d92f936cf10d 1030
MPPT51 0:d92f936cf10d 1031 cellVoltages[i] = adcVal * adcGain / 1000 + adcOffset;
MPPT51 0:d92f936cf10d 1032 printf("%d, %d, %d, %d\n\r", cellVoltages[i], adcVal, adcGain, adcOffset);
MPPT51 0:d92f936cf10d 1033
MPPT51 0:d92f936cf10d 1034 if (cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1035 connectedCellsTemp++;
MPPT51 0:d92f936cf10d 1036 }
MPPT51 0:d92f936cf10d 1037 if (cellVoltages[i] > cellVoltages[idCellMaxVoltage]) {
MPPT51 0:d92f936cf10d 1038 idCellMaxVoltage = i;
MPPT51 0:d92f936cf10d 1039 }
MPPT51 0:d92f936cf10d 1040 if (cellVoltages[i] < cellVoltages[idCellMinVoltage] && cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1041 idCellMinVoltage = i;
MPPT51 0:d92f936cf10d 1042 }
MPPT51 0:d92f936cf10d 1043 }
MPPT51 0:d92f936cf10d 1044 connectedCells = connectedCellsTemp;
MPPT51 0:d92f936cf10d 1045
MPPT51 0:d92f936cf10d 1046 // read battery pack voltage
MPPT51 0:d92f936cf10d 1047 adcVal = (readRegister(BAT_HI_BYTE) << 8) | readRegister(BAT_LO_BYTE);
MPPT51 0:d92f936cf10d 1048 batVoltage = 4.0 * adcGain * adcVal / 1000.0 + connectedCells * adcOffset;
MPPT51 0:d92f936cf10d 1049 }
MPPT51 0:d92f936cf10d 1050
MPPT51 0:d92f936cf10d 1051 void bq769x0::updateVoltages1()
MPPT51 0:d92f936cf10d 1052 {
MPPT51 0:d92f936cf10d 1053 bms1_on = 1;
MPPT51 0:d92f936cf10d 1054 wait(0.3);
MPPT51 0:d92f936cf10d 1055
MPPT51 0:d92f936cf10d 1056 long adcVal = 0;
MPPT51 0:d92f936cf10d 1057 char buf[4];
MPPT51 0:d92f936cf10d 1058 int connectedCellsTemp = 0;
MPPT51 0:d92f936cf10d 1059
MPPT51 0:d92f936cf10d 1060 // read cell voltages
MPPT51 0:d92f936cf10d 1061 buf[0] = (char) VC1_HI_BYTE;
MPPT51 0:d92f936cf10d 1062 _i2c.write(I2CAddress << 1, buf, 1);
MPPT51 0:d92f936cf10d 1063 //printf("Tx1:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1064
MPPT51 0:d92f936cf10d 1065 idCellMaxVoltage = 0;
MPPT51 0:d92f936cf10d 1066 idCellMinVoltage = 0;
MPPT51 0:d92f936cf10d 1067 for (int i = 0; i < numberOfCells; i++)
MPPT51 0:d92f936cf10d 1068 {
MPPT51 0:d92f936cf10d 1069 _i2c.read(I2CAddress << 1, buf, 2);
MPPT51 0:d92f936cf10d 1070 adcVal = (buf[0] & 0b00111111) << 8 | buf[1];
MPPT51 0:d92f936cf10d 1071 //printf("Rx1:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1072
MPPT51 0:d92f936cf10d 1073 cellVoltages[i] = adcVal * adcGain1 / 1000 + adcOffset1;
MPPT51 0:d92f936cf10d 1074 //printf("1:%d, %d, %d, %d\n\r", cellVoltages[i], adcVal, adcGain1, adcOffset1);
MPPT51 0:d92f936cf10d 1075
MPPT51 0:d92f936cf10d 1076 if (cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1077 connectedCellsTemp++;
MPPT51 0:d92f936cf10d 1078 }
MPPT51 0:d92f936cf10d 1079 if (cellVoltages[i] > cellVoltages[idCellMaxVoltage]) {
MPPT51 0:d92f936cf10d 1080 idCellMaxVoltage = i;
MPPT51 0:d92f936cf10d 1081 }
MPPT51 0:d92f936cf10d 1082 if (cellVoltages[i] < cellVoltages[idCellMinVoltage] && cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1083 idCellMinVoltage = i;
MPPT51 0:d92f936cf10d 1084 }
MPPT51 0:d92f936cf10d 1085 }
MPPT51 0:d92f936cf10d 1086 connectedCells = connectedCellsTemp;
MPPT51 0:d92f936cf10d 1087
MPPT51 0:d92f936cf10d 1088 // read battery pack voltage
MPPT51 0:d92f936cf10d 1089 adcVal = (readRegister(BAT_HI_BYTE) << 8) | readRegister(BAT_LO_BYTE);
MPPT51 0:d92f936cf10d 1090 batVoltage = 4.0 * adcGain * adcVal / 1000.0 + connectedCells * adcOffset;
MPPT51 0:d92f936cf10d 1091
MPPT51 0:d92f936cf10d 1092 bms1_on = 0;
MPPT51 0:d92f936cf10d 1093 }
MPPT51 0:d92f936cf10d 1094
MPPT51 0:d92f936cf10d 1095 void bq769x0::updateVoltages2()
MPPT51 0:d92f936cf10d 1096 {
MPPT51 0:d92f936cf10d 1097 bms2_on = 1;
MPPT51 0:d92f936cf10d 1098 wait(0.3);
MPPT51 0:d92f936cf10d 1099 long adcVal = 0;
MPPT51 0:d92f936cf10d 1100 char buf[4];
MPPT51 0:d92f936cf10d 1101 int connectedCellsTemp = 0;
MPPT51 0:d92f936cf10d 1102
MPPT51 0:d92f936cf10d 1103 // read cell voltages
MPPT51 0:d92f936cf10d 1104 buf[0] = (char) VC1_HI_BYTE;
MPPT51 0:d92f936cf10d 1105 _i2c.write(I2CAddress << 1, buf, 1);
MPPT51 0:d92f936cf10d 1106 //printf("Tx2:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1107
MPPT51 0:d92f936cf10d 1108 idCellMaxVoltage = 0;
MPPT51 0:d92f936cf10d 1109 idCellMinVoltage = 0;
MPPT51 0:d92f936cf10d 1110 for (int i = 0; i < numberOfCells; i++)
MPPT51 0:d92f936cf10d 1111 {
MPPT51 0:d92f936cf10d 1112 _i2c.read(I2CAddress << 1, buf, 2);
MPPT51 0:d92f936cf10d 1113 adcVal = (buf[0] & 0b00111111) << 8 | buf[1];
MPPT51 0:d92f936cf10d 1114 //printf("Rx2:%x, %x, %d, %d\n\r", buf[0], buf[1], buf[0], buf[1]);
MPPT51 0:d92f936cf10d 1115
MPPT51 0:d92f936cf10d 1116 cellVoltages[i] = adcVal * adcGain2 / 1000 + adcOffset2;
MPPT51 0:d92f936cf10d 1117 //printf("2:%d, %d, %d, %d\n\r", cellVoltages[i], adcVal, adcGain2, adcOffset2);
MPPT51 0:d92f936cf10d 1118
MPPT51 0:d92f936cf10d 1119 if (cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1120 connectedCellsTemp++;
MPPT51 0:d92f936cf10d 1121 }
MPPT51 0:d92f936cf10d 1122 if (cellVoltages[i] > cellVoltages[idCellMaxVoltage]) {
MPPT51 0:d92f936cf10d 1123 idCellMaxVoltage = i;
MPPT51 0:d92f936cf10d 1124 }
MPPT51 0:d92f936cf10d 1125 if (cellVoltages[i] < cellVoltages[idCellMinVoltage] && cellVoltages[i] > 500) {
MPPT51 0:d92f936cf10d 1126 idCellMinVoltage = i;
MPPT51 0:d92f936cf10d 1127 }
MPPT51 0:d92f936cf10d 1128 }
MPPT51 0:d92f936cf10d 1129 connectedCells = connectedCellsTemp;
MPPT51 0:d92f936cf10d 1130
MPPT51 0:d92f936cf10d 1131 // read battery pack voltage
MPPT51 0:d92f936cf10d 1132 adcVal = (readRegister(BAT_HI_BYTE) << 8) | readRegister(BAT_LO_BYTE);
MPPT51 0:d92f936cf10d 1133 batVoltage = 4.0 * adcGain * adcVal / 1000.0 + connectedCells * adcOffset;
MPPT51 0:d92f936cf10d 1134
MPPT51 0:d92f936cf10d 1135 bms2_on = 0;
MPPT51 0:d92f936cf10d 1136 }
MPPT51 0:d92f936cf10d 1137
MPPT51 0:d92f936cf10d 1138 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 1139
MPPT51 0:d92f936cf10d 1140 void bq769x0::writeRegister(int address, int data)
MPPT51 0:d92f936cf10d 1141 {
MPPT51 0:d92f936cf10d 1142 uint8_t crc = 0;
MPPT51 0:d92f936cf10d 1143 char buf[3];
MPPT51 0:d92f936cf10d 1144
MPPT51 0:d92f936cf10d 1145 buf[0] = (char) address;
MPPT51 0:d92f936cf10d 1146 buf[1] = data;
MPPT51 0:d92f936cf10d 1147
MPPT51 0:d92f936cf10d 1148 if (crcEnabled == true) {
MPPT51 0:d92f936cf10d 1149 // CRC is calculated over the slave address (including R/W bit), register address, and data.
MPPT51 0:d92f936cf10d 1150 crc = _crc8_ccitt_update(crc, (I2CAddress << 1) | 0);
MPPT51 0:d92f936cf10d 1151 crc = _crc8_ccitt_update(crc, buf[0]);
MPPT51 0:d92f936cf10d 1152 crc = _crc8_ccitt_update(crc, buf[1]);
MPPT51 0:d92f936cf10d 1153 buf[2] = crc;
MPPT51 0:d92f936cf10d 1154 _i2c.write(I2CAddress << 1, buf, 3);
MPPT51 0:d92f936cf10d 1155 }
MPPT51 0:d92f936cf10d 1156 else {
MPPT51 0:d92f936cf10d 1157 _i2c.write(I2CAddress << 1, buf, 2);
MPPT51 0:d92f936cf10d 1158 }
MPPT51 0:d92f936cf10d 1159 }
MPPT51 0:d92f936cf10d 1160
MPPT51 0:d92f936cf10d 1161 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 1162
MPPT51 0:d92f936cf10d 1163 int bq769x0::readRegister(int address)
MPPT51 0:d92f936cf10d 1164 {
MPPT51 0:d92f936cf10d 1165 uint8_t crc = 0;
MPPT51 0:d92f936cf10d 1166 char buf[2];
MPPT51 0:d92f936cf10d 1167
MPPT51 0:d92f936cf10d 1168 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 1169 //printf("Read register: 0x%x \n", address);
MPPT51 0:d92f936cf10d 1170 #endif
MPPT51 0:d92f936cf10d 1171
MPPT51 0:d92f936cf10d 1172 buf[0] = (char)address;
MPPT51 0:d92f936cf10d 1173 _i2c.write(I2CAddress << 1, buf, 1);;
MPPT51 0:d92f936cf10d 1174
MPPT51 0:d92f936cf10d 1175 if (crcEnabled == true) {
MPPT51 0:d92f936cf10d 1176 do {
MPPT51 0:d92f936cf10d 1177 _i2c.read(I2CAddress << 1, buf, 2);
MPPT51 0:d92f936cf10d 1178 // CRC is calculated over the slave address (including R/W bit) and data.
MPPT51 0:d92f936cf10d 1179 crc = _crc8_ccitt_update(crc, (I2CAddress << 1) | 1);
MPPT51 0:d92f936cf10d 1180 crc = _crc8_ccitt_update(crc, buf[0]);
MPPT51 0:d92f936cf10d 1181 } while (crc != buf[1]);
MPPT51 0:d92f936cf10d 1182 return buf[0];
MPPT51 0:d92f936cf10d 1183 }
MPPT51 0:d92f936cf10d 1184 else {
MPPT51 0:d92f936cf10d 1185 _i2c.read(I2CAddress << 1, buf, 1);
MPPT51 0:d92f936cf10d 1186 return buf[0];
MPPT51 0:d92f936cf10d 1187 }
MPPT51 0:d92f936cf10d 1188 }
MPPT51 0:d92f936cf10d 1189
MPPT51 0:d92f936cf10d 1190 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 1191 // The bq769x0 drives the ALERT pin high if the SYS_STAT register contains
MPPT51 0:d92f936cf10d 1192 // a new value (either new CC reading or an error)
MPPT51 0:d92f936cf10d 1193
MPPT51 0:d92f936cf10d 1194 void bq769x0::setAlertInterruptFlag()
MPPT51 0:d92f936cf10d 1195 {
MPPT51 0:d92f936cf10d 1196 interruptTimestamp = _timer.read_ms();
MPPT51 0:d92f936cf10d 1197 alertInterruptFlag = true;
MPPT51 0:d92f936cf10d 1198 }
MPPT51 0:d92f936cf10d 1199
MPPT51 0:d92f936cf10d 1200 #if BQ769X0_DEBUG
MPPT51 0:d92f936cf10d 1201
MPPT51 0:d92f936cf10d 1202 //----------------------------------------------------------------------------
MPPT51 0:d92f936cf10d 1203 // for debug purposes
MPPT51 0:d92f936cf10d 1204
MPPT51 0:d92f936cf10d 1205 void bq769x0::printRegisters()
MPPT51 0:d92f936cf10d 1206 {
MPPT51 0:d92f936cf10d 1207 printf("0x00 SYS_STAT: %s\n", byte2char(readRegister(SYS_STAT)));
MPPT51 0:d92f936cf10d 1208 printf("0x01 CELLBAL1: %s\n", byte2char(readRegister(CELLBAL1)));
MPPT51 0:d92f936cf10d 1209 printf("0x04 SYS_CTRL1: %s\n", byte2char(readRegister(SYS_CTRL1)));
MPPT51 0:d92f936cf10d 1210 printf("0x05 SYS_CTRL2: %s\n", byte2char(readRegister(SYS_CTRL2)));
MPPT51 0:d92f936cf10d 1211 printf("0x06 PROTECT1: %s\n", byte2char(readRegister(PROTECT1)));
MPPT51 0:d92f936cf10d 1212 printf("0x07 PROTECT2: %s\n", byte2char(readRegister(PROTECT2)));
MPPT51 0:d92f936cf10d 1213 printf("0x08 PROTECT3: %s\n", byte2char(readRegister(PROTECT3)));
MPPT51 0:d92f936cf10d 1214 printf("0x09 OV_TRIP: %s\n", byte2char(readRegister(OV_TRIP)));
MPPT51 0:d92f936cf10d 1215 printf("0x0A UV_TRIP: %s\n", byte2char(readRegister(UV_TRIP)));
MPPT51 0:d92f936cf10d 1216 printf("0x0B CC_CFG: %s\n", byte2char(readRegister(CC_CFG)));
MPPT51 0:d92f936cf10d 1217 printf("0x32 CC_HI: %s\n", byte2char(readRegister(CC_HI_BYTE)));
MPPT51 0:d92f936cf10d 1218 printf("0x33 CC_LO: %s\n", byte2char(readRegister(CC_LO_BYTE)));
MPPT51 0:d92f936cf10d 1219 /*
MPPT51 0:d92f936cf10d 1220 printf("0x50 ADCGAIN1: %s\n", byte2char(readRegister(ADCGAIN1)));
MPPT51 0:d92f936cf10d 1221 printf("0x51 ADCOFFSET: %s\n", byte2char(readRegister(ADCOFFSET)));
MPPT51 0:d92f936cf10d 1222 printf("0x59 ADCGAIN2: %s\n", byte2char(readRegister(ADCGAIN2)));
MPPT51 0:d92f936cf10d 1223 */
MPPT51 0:d92f936cf10d 1224 }
MPPT51 0:d92f936cf10d 1225
MPPT51 0:d92f936cf10d 1226 #endif
MPPT51 0:d92f936cf10d 1227