-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathBMSModule.cpp
More file actions
371 lines (333 loc) · 12.5 KB
/
BMSModule.cpp
File metadata and controls
371 lines (333 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#include "BMSModule.hpp"
#include "BMSDriver.hpp"
#include "Logger.hpp"
/////////////////////////////////////////////////
/// \brief BMSModule constructor initialized to invalid address 0.
///
/// It's important for the constructor to be without arguments.
/// This allows instantiating all 0x3E modules on the .bss instead of the stack.
/////////////////////////////////////////////////
BMSModule::BMSModule()
{
resetRecordedValues();
moduleAddress = 0;
}
/////////////////////////////////////////////////
/// \brief Reset all the values of the object recorded since last reset.
///
/// The prefered way of reseting all values is through a soft board reset using the push button.
/// This function can be used to only reinitialize the values without reseting the whole board.
/////////////////////////////////////////////////
void BMSModule::resetRecordedValues()
{
for (int i = 0; i < 6; i++)
{
cellVolt[i] = 0.0f;
lowestCellVolt[i] = 5.0f;
highestCellVolt[i] = 0.0f;
}
moduleVolt = 0.0f;
retmoduleVolt = 0.0f;
temperatures[0] = 0.0f;
temperatures[1] = 0.0f;
lowestTemperature = 200.0f;
highestTemperature = -100.0f;
lowestModuleVolt = 200.0f;
highestModuleVolt = 0.0f;
}
/////////////////////////////////////////////////
/// \brief Balance the cells of the module associated to this object according to the cell mask.
///
/// When balancing is used on a module it will only balance the cells identified by the cellMask for balanceTime seconds.
/// @param cellMask is a byte where the msb = cell0 and bit5 is cell5.
/// @param balanceTime time in seconds (up to 5 seconds) that the cells sheding resistor should be enabled.
/////////////////////////////////////////////////
bool BMSModule::balanceCells(uint8_t cellMask, uint8_t balanceTime) {
int16_t err;
//BalanceCells time
if ((err = BMSDW(moduleAddress, REG_BAL_TIME, balanceTime)) < 0) {
BMSD_LOG_ERR(moduleAddress, err, "BalanceCells time");
return false;
}
//write balance state to register
if ((err = BMSDW(moduleAddress, REG_BAL_CTRL, cellMask)) < 0) {
BMSD_LOG_ERR(moduleAddress, err, "BalanceCells mask");
return false;
}
return true;
}
/////////////////////////////////////////////////
/// \brief This function fetches all the data from the physical tesla module and populates its atributes.
///
/// This function is meant to be called periodically so that the controller can make decision based on the state of the module.
/// The data collected are the faults, the reading of the two temperature sensors and the voltage reading from all 6 cells.
/////////////////////////////////////////////////
bool BMSModule::updateInstanceWithModuleValues()
{
uint8_t buff[50];
int16_t err;
float tempCalc;
float tempTemp;
/*
Status registers
*/
//BMSDR(moduleAddress, REG_DEV_STATUS, 1, buff);
//BMSDR(moduleAddress, REG_BAL_TIME, 1, buff);
if ((err = BMSDR(moduleAddress, REG_ALERT_STATUS, 4, buff)) > 0) {
alerts = buff[0];
faults = buff[1];
COVFaults = buff[2];
CUVFaults = buff[3];
LOG_DEBUG("Module %i alerts=%X faults=%X COV=%X CUV=%X\n", moduleAddress, alerts, faults, COVFaults, CUVFaults);
} else {
BMSD_LOG_ERR(moduleAddress, err, "Reading Status Registers");
return false;
}
/*
Voltage and Temperature registers
*/
//ADC Auto mode, read every ADC input we can (Both Temps, Pack, 6 cells)
if ((err = BMSDW(moduleAddress, REG_ADC_CTRL, 0b00111101)) < 0) {
BMSD_LOG_ERR(moduleAddress, err, "ADC Auto mode");
return false;
}
//enable temperature measurement VSS pins
if ((err = BMSDW(moduleAddress, REG_IO_CTRL, 0b00000011)) < 0) {
BMSD_LOG_ERR(moduleAddress, err, "enable temperature measurement VSS pins");
return false;
}
//start all ADC conversions
if ((err = BMSDW(moduleAddress, REG_ADC_CONV, 1)) < 0) {
BMSD_LOG_ERR(moduleAddress, err, "start all ADC conversions");
return false;
}
//start reading registers at the module voltage registers
//read 18 bytes (Each value takes 2 - ModuleV, CellV1-6, Temp1, Temp2)
if ((err = BMSDR(moduleAddress, REG_GPAI, 0x12, buff)) > 0) {
//payload is 2 bytes gpai, 2 bytes for each of 6 cell voltages, 2 bytes for each of two temperatures (18 bytes of data)
retmoduleVolt = (buff[0] * 256 + buff[1]) * 0.0020346293922562f;//0.002034609f;
if (retmoduleVolt > highestModuleVolt) highestModuleVolt = retmoduleVolt;
if (retmoduleVolt < lowestModuleVolt) lowestModuleVolt = retmoduleVolt;
for (int i = 0; i < 6; i++)
{
cellVolt[i] = (buff[2 + (i * 2)] * 256 + buff[3 + (i * 2)]) * 0.000381493f;
if (lowestCellVolt[i] > cellVolt[i]) lowestCellVolt[i] = cellVolt[i];
if (highestCellVolt[i] < cellVolt[i]) highestCellVolt[i] = cellVolt[i];
}
//use added up cells and not reported module voltage
moduleVolt = 0;
for (int i = 0; i < 6; i++)
{
moduleVolt = moduleVolt + cellVolt[i];
}
} else {
BMSD_LOG_ERR(moduleAddress, err, "Reading voltage registers");
return false;
}
//Now using steinhart/hart equation for temperatures. We'll see if it is better than old code.
tempTemp = (1.78f / ((buff[14] * 256 + buff[15] + 2) / 33046.0f) - 3.57f);
tempTemp *= 1000.0f;
tempCalc = 1.0f / (0.0007610373573f + (0.0002728524832 * logf(tempTemp)) + (powf(logf(tempTemp), 3) * 0.0000001022822735f));
temperatures[0] = tempCalc - 273.15f;
tempTemp = 1.78f / ((buff[16] * 256 + buff[17] + 9) / 33068.0f) - 3.57f;
tempTemp *= 1000.0f;
tempCalc = 1.0f / (0.0007610373573f + (0.0002728524832 * logf(tempTemp)) + (powf(logf(tempTemp), 3) * 0.0000001022822735f));
temperatures[1] = tempCalc - 273.15f;
if (getLowTemp() < lowestTemperature) lowestTemperature = getLowTemp();
if (getHighTemp() > highestTemperature) highestTemperature = getHighTemp();
LOG_DEBUG("Got voltage and temperature readings\n");
return true;
}
/////////////////////////////////////////////////
/// \brief returns the faults registered in this module.
///
/// | bool mask | hex mask | fault description |
/// |:---------:|:--------:|-------------------|
/// |0b00000001 | 0x01 | Cell Over Voltage, check COVFaults to identify affected cells.|
/// |0b00000010 | 0x02 | Cell Under Voltage, check CUVFaults to identify affected cells.|
/// |0b00000100 | 0x04 | CRC error in received packet.|
/// |0b00001000 | 0x08 | Power on reset has occurred.|
/// |0b00010000 | 0x10 | Test fault active.|
/// |0b00100000 | 0x20 | Internal registers inconsistent.|
/////////////////////////////////////////////////
uint8_t BMSModule::getFaults()
{
return faults;
}
/////////////////////////////////////////////////
/// \brief returns the alerts registered in this module.
///
/// | bool mask | hex mask | Alert description |
/// |:---------:|:--------:|-------------------|
/// |0b00000001 | 0x01 | Over temperature on TS1.|
/// |0b00000010 | 0x02 | Over temperature on TS2.|
/// |0b00000100 | 0x04 | Sleep mode active.|
/// |0b00001000 | 0x08 | Thermal shutdown active.|
/// |0b00010000 | 0x10 | Test Alert.|
/// |0b00100000 | 0x20 | OTP EPROM Uncorrectable Error.|
/// |0b01000000 | 0x40 | GROUP3 Regs Invalid.|
/// |0b10000000 | 0x80 | Address not registered.|
/////////////////////////////////////////////////
uint8_t BMSModule::getAlerts()
{
return alerts;
}
/////////////////////////////////////////////////
/// \brief returns a bit map of the OV cells.
//////////////////////////////////////////////////
uint8_t BMSModule::getCOVCells()
{
return COVFaults;
}
/////////////////////////////////////////////////
/// \brief returns a bit map of the UV cells.
//////////////////////////////////////////////////
uint8_t BMSModule::getCUVCells()
{
return CUVFaults;
}
/////////////////////////////////////////////////
/// \brief returns the voltage of a cell.
///
/// @param cell The cell index
//////////////////////////////////////////////////
float BMSModule::getCellVoltage(int cell)
{
if (cell < 0 || cell > 5) return 0.0f;
return cellVolt[cell];
}
/////////////////////////////////////////////////
/// \brief returns the voltage of the lowest voltage cell.
//////////////////////////////////////////////////
float BMSModule::getLowCellV()
{
float lowVal = 10.0f;
for (int i = 0; i < 6; i++) if (cellVolt[i] < lowVal) lowVal = cellVolt[i];
return lowVal;
}
/////////////////////////////////////////////////
/// \brief returns the voltage of the highest voltage cell.
//////////////////////////////////////////////////
float BMSModule::getHighCellV()
{
float hiVal = 0.0f;
for (int i = 0; i < 6; i++) if (cellVolt[i] > hiVal) hiVal = cellVolt[i];
return hiVal;
}
/////////////////////////////////////////////////
/// \brief returns the average voltage of all 6 cells within this module.
//////////////////////////////////////////////////
float BMSModule::getAverageV()
{
int x = 0;
float avgVal = 0.0f;
for (int i = 0; i < 6; i++)
{
if (cellVolt[i] < 60.0)
{
x++;
avgVal += cellVolt[i];
}
}
avgVal /= x;
return avgVal;
}
/////////////////////////////////////////////////
/// \brief returns the highest voltage reached by a cell since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getHighestModuleVolt()
{
return highestModuleVolt;
}
/////////////////////////////////////////////////
/// \brief returns the lowest voltage reached by a cell since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getLowestModuleVolt()
{
return lowestModuleVolt;
}
/////////////////////////////////////////////////
/// \brief returns the highest voltage reached by each individual cells since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getHighestCellVolt(int cell)
{
if (cell < 0 || cell > 5) return 0.0f;
return highestCellVolt[cell];
}
/////////////////////////////////////////////////
/// \brief returns the lowest voltage reached by a cell since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getLowestCellVolt(int cell)
{
if (cell < 0 || cell > 5) return 0.0f;
return lowestCellVolt[cell];
}
/////////////////////////////////////////////////
/// \brief returns the highest temperature reached by the module since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getHighestTemp()
{
return highestTemperature;
}
/////////////////////////////////////////////////
/// \brief returns the lowest temperature reached by the module since last reset of the atributes.
//////////////////////////////////////////////////
float BMSModule::getLowestTemp()
{
return lowestTemperature;
}
/////////////////////////////////////////////////
/// \brief returns the lower temperature of the two temperature sensors.
//////////////////////////////////////////////////
float BMSModule::getLowTemp()
{
return (temperatures[0] < temperatures[1]) ? temperatures[0] : temperatures[1];
}
/////////////////////////////////////////////////
/// \brief returns the higher temperature of the two temperature sensors.
//////////////////////////////////////////////////
float BMSModule::getHighTemp()
{
return (temperatures[0] < temperatures[1]) ? temperatures[1] : temperatures[0];
}
/////////////////////////////////////////////////
/// \brief returns the average temperature of the two temperature sensors.
//////////////////////////////////////////////////
float BMSModule::getAvgTemp()
{
return (temperatures[0] + temperatures[1]) / 2.0f;
}
/////////////////////////////////////////////////
/// \brief returns the module voltage.
//////////////////////////////////////////////////
float BMSModule::getModuleVoltage()
{
return moduleVolt;
}
/////////////////////////////////////////////////
/// \brief returns the temperature reading of a temperature sensor.
///
/// @param temp temp sensor index (0 or 1)
//////////////////////////////////////////////////
float BMSModule::getTemperature(int temp)
{
if (temp < 0 || temp > 1) return 0.0f;
return temperatures[temp];
}
/////////////////////////////////////////////////
/// \brief Sets the address of the module associated to this object instance.
///
/// @param newAddr The address to assign to this module (0 - 0x3e). 0 would mean the module is not used.
//////////////////////////////////////////////////
void BMSModule::setAddress(uint8_t newAddr)
{
if (newAddr < 0 || newAddr > MAX_MODULE_ADDR) return;
moduleAddress = newAddr;
}
/////////////////////////////////////////////////
/// \brief Returns the address of the module associated to this object instance.
//////////////////////////////////////////////////
uint8_t BMSModule::getAddress()
{
return moduleAddress;
}