DC2100A  1.2.0
Bi-Directional Cell Balancer Using the LTC3300-1 and the LTC6804-2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Balancer.c
Go to the documentation of this file.
1 /*
2  Linear Technology DC2100A Demonstration Board.
3  Reference Application File for Controlling the LTC3300-1 Battery Balancers through the LTC6804-2 Battery Monitor on the DC2100A PCB.
4 
5  @verbatim
6  This file contains a task to control the balancers in the DC2100A System with a resolution set by BALANCER_TASK_RATE, as well as functions
7  to control and monitor the balancer task.
8  @endverbatim
9 
10  http://www.linear.com/solutions/5126
11 
12  REVISION HISTORY
13  $Revision: 697 $
14  $Date: 2014-09-09 15:15:44 -0400 (Tue, 09 Sep 2014) $
15 
16  Copyright (c) 2013, Linear Technology Corp.(LTC)
17  All rights reserved.
18 
19  Redistribution and use in source and binary forms, with or without
20  modification, are permitted provided that the following conditions are met:
21 
22  1. Redistributions of source code must retain the above copyright notice, this
23  list of conditions and the following disclaimer.
24  2. Redistributions in binary form must reproduce the above copyright notice,
25  this list of conditions and the following disclaimer in the documentation
26  and/or other materials provided with the distribution.
27 
28  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
32  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 
39  The views and conclusions contained in the software and documentation are those
40  of the authors and should not be interpreted as representing official policies,
41  either expressed or implied, of Linear Technology Corp.
42 
43 */
44 
45 //! @defgroup Balancer Reference Application File for Controlling the LTC3300-1 Battery Balancers through the LTC6804-2 Battery Monitor on the DC2100A PCB.
46 
47 /*! @file
48  @ingroup Balancer
49  Reference Application File for Controlling the LTC3300-1 Battery Balancers through the LTC6804-2 Battery Monitor on the DC2100A PCB.
50 */
51 
52 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
53 // Includes
54 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
55 #include "Typedefs.h"
56 #include "LTC3300-1.h"
57 #include "DC2100A.h"
58 #include "Balancer.h"
59 #include "LTC6804-2.h"
60 #include "Eeprom.h"
61 #include <string.h>
62 
63 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
64 // Definitions
65 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
66 
67 // Constants for configuration of Balancer_Set(BALANCER_DELTA_Q_TYPE* charge_target_ptr) function
68 // See "CapDemo Balancing Algorithm" worksheet in DC2100A_Design.xlsm for a model of this function, and the meaning of these constants.
69 #define BALANCER_ALGORITHM_NUM_BOARDS 1 // Note - the Balancer_Set(BALANCER_DELTA_Q_TYPE* charge_target_ptr) function is limited to this many boards.
70 #define BALANCER_ALGORITHM_PASSES 10 // The number of iterations algorithm performs to determine optimal active balance states to achieve desired delta Q.
71 
72 #define BALANCER_TIME_RESOLUTION_SHIFT 2 // Division
73 #define BALANCER_TIME_RESOLUTION (1L << BALANCER_TIME_RESOLUTION_SHIFT)
74 #if BALANCER_TIME_RESOLUTION != (MS_PER_S/BALANCER_TASK_RATE)
75 #error The balancer task must be called at the frequency necessary to provide the desired resolution in balance time.
76 #endif
77 
78 #define BALANCER_CHARGE_EFFICIENCY 92 // in %, efficiency of balancer when charging a cell
79 #define BALANCER_DISCHARGE_EFFICIENCY 92 // in %, efficiency of balancer when discharging a cell
80 #define BALANCER_CELL_CHARGE_ERROR_DAMPING_SHIFT 1 // Damping factor for cell charge error feedback term in iterative calaculation
81 #define BALANCER_CELL_CHARGE_ERROR_DAMPING (1L << BALANCER_CELL_CHARGE_ERROR_DAMPING_SHIFT)
82 #define BALANCER_HALF_STACK_EEROR_DAMPING_SHIFT 1
83 #define BALANCER_HALF_STACK_EEROR_DAMPING (1L << BALANCER_HALF_STACK_EEROR_DAMPING_SHIFT)
84 //! @}
85 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
86 // Global Data
87 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
88 
89 BALANCER_ACTIVE_STATE_TYPE Balancer_Active_State[DC2100A_MAX_BOARDS][DC2100A_NUM_CELLS]; // The state of each active cell balancer on each DC2100A in the system.
90 BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Max; // The longest active balance time in the DC2100A system.
91 BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Next_Stop; // The shortest, yet non-zero, active balance time in the DC2100A system.
92 int8 Balancer_Active_Board_Max; // The board with the longest remaining balance time
93 int8 Balancer_Active_Board_Next_Stop; // The cell with the shortest, yet non-zero, remaining balance time
94 BALANCER_PASSIVE_STATE_TYPE Balancer_Passive_State[DC2100A_MAX_BOARDS]; // Bitmap for LTC6804_NUM_CELLV_ADC passive balancers on one DC2100A, 1 = ON and 0 = Off, bit 0 = cell 0
95 
96 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
97 // Local Data
98 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
99 BALANCER_CONTROL_STATE_TYPE balancer_control_state; // State in which the balancer task is currently operating
100 int8 balancer_watchdog_counter; // Counter for how often balancer task needs to send watchdog commands to prevent LTC3300-1 from goign to sleep.
101 BOOLEAN balancer_synchronous_mode; // TRUE if LTC3300-1 are to be operated in Synchronous mode.
102 unsigned int16 balancer_gate_drive_ok[DC2100A_MAX_BOARDS]; // Bitmap for gate drive signal status bits, where bit 0 is cell 1. Note that these are 0 if balancer is not on, as well as if gate drive is not ok.
103 unsigned int16 balancer_cells_ov_ok; // Bitmap for cells overvoltage status bits, where bit 0 is board 0. 1 indicates that cells are not overvoltaged.
104 unsigned int16 balancer_stack_ov_ok; // Bitmap for stack overvoltage status bits, where bit 0 is board 0. 1 indicates that stack is not overvoltaged.
105 unsigned int16 balancer_temperature_ok; // Bitmap for temperature ok, where bit 0 is board 0. 1 indicates that stack is not overtemperature.
106 
107 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
108 // Local Prototypes
109 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
110 void balancer_command_update(int8 board_num);
111 void balancer_nextstop_update(int8 board_num, int16 bal_timer);
112 void balancer_max_and_nextstop_update(int8 board_num, BALANCER_ACTIVE_STATE_TYPE balancer_state);
113 void balancer_status_update(int8 board_num);
114 
115 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
116 // Global Functions
117 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
118 
119 // Initializes the parts of the Balancer Module, that need to be initialized upon power-up of the PIC.
120 void Balancer_Init(void)
121 {
122  memset(Balancer_Active_State, 0, sizeof(Balancer_Active_State));
124 
125  balancer_control_state = BALANCER_CONTROL_OFF;
126  balancer_watchdog_counter = LTC3300_TWD1 / BALANCER_TASK_RATE;
127 
132 
133  memset(balancer_gate_drive_ok, 0, sizeof(balancer_gate_drive_ok));
134  balancer_cells_ov_ok = 0;
135  balancer_stack_ov_ok = 0;
136  balancer_temperature_ok = 0;
137 
138  balancer_synchronous_mode = TRUE;
139 
140 }
141 
142 // Initializes the parts of the Balancer Module, that need to be initialized upon wakeup of the LTC3300-1.
143 BOOLEAN Balancer_Wakeup_Init(void)
144 {
145  BOOLEAN success = TRUE;
146  int8 cell_num;
147  int8 balancer_command[DC2100A_NUM_CELLS];
148 
149  // Balance commands are not cleared in the LTC3300, after waking from sleep.
150  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
151  {
152  // If timer has expired, then turn balancer off
153  balancer_command[cell_num] = LTC3300_BALANCER_CONTROL_CODE_NONE;
154  }
155 
156  // Clear balance commands to the LTC3300s for the boards in this system
157  LTC3300_Command_Write(LTC6804_BROADCAST, balancer_command);
158 
159  return success;
160 }
161 
162 // Executes the Balancer Control task.
163 // - Sends watchdog commands to the LTC3300-1 ICs to keep them awake, unless in a state which allows the LTC3300-1 ICs to sleep.
164 // - If in the BALANCER_CONTROL_ON state, each active cell balancer command has its timer decremented while sending the appropriate commands
165 // to the LTC3300-1 ICs. The max and min (yet non-zero) balance times are tracked in this state.
166 // - Turns on/off the passive balancers.
167 // - Monitors the state of the balancers.
169 {
170  int8 board_num;
171  int8 cell_num;
172  int16 bal_timer;
173 
174  // Update the watchdog counter. The reset will be handled depending upon the case.
175  if(balancer_watchdog_counter != 0)
176  {
177  balancer_watchdog_counter--;
178  }
179 
180  switch (balancer_control_state)
181  {
182  default:
184  // Not balancing, do not send commands to allow LTC3300 to turn off.
185  balancer_watchdog_counter = LTC3300_TWD1 / BALANCER_TASK_RATE;
186  break;
187 
189  // Kick WDT but nothing else, to allow GUI directly talk to the LTC3300s
190  if(balancer_watchdog_counter == 0)
191  {
193  balancer_watchdog_counter = LTC3300_TWD1 / BALANCER_TASK_RATE;
194  }
195  break;
196 
198  // Kick WDT.
199  if(balancer_watchdog_counter == 0)
200  {
202  balancer_watchdog_counter = LTC3300_TWD1 / BALANCER_TASK_RATE;
203  }
204 
205  for (board_num = 0; board_num < System_Num_Boards; board_num++)
206  {
207  // Update the balancer commands in the LTC3300s
208  balancer_command_update(board_num);
209  }
210  break;
211 
212  case BALANCER_CONTROL_ON:
213  // Send commands to the LTC3300. Update first, in case the BALANCER_CONTROL_SETUP state was skipped.
214  // Worst case we need enough communication time for when all of the cells change balance state at once.
215  // A simple way to ensure this is to update all of the cells all of the time.
216  for (board_num = 0; board_num < System_Num_Boards; board_num++)
217  {
218  balancer_command_update(board_num);
219  }
220 
221  // Execute the loaded command. Note that loaded commands don't change the balancer output until a subsequent Execute command is received.
223 
224  // The next time that this task is run, all of the times will be zero.
225  // Move to suspend so that the state reflects if we are actually balancing.
226  if(Balancer_Active_Time_Max == 0)
227  {
228  balancer_control_state = BALANCER_CONTROL_OFF;
229  }
230  else
231  {
232  // decrement the max and next stop timers.
235  {
237  }
238 
239  // Count down the balancing time for each board, and update the balance commands.
240  // Note that the balancers are actually turned off next time task is run.
241  for (board_num = 0; board_num < System_Num_Boards; board_num++)
242  {
243  // decrement the count for all cells.
244  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
245  {
246 
247  bal_timer = (Balancer_Active_State[board_num][cell_num] & BALANCER_ACTIVE_STATE_TIME_MASK);
248  if(bal_timer == 0)
249  {
251  }
252  else
253  {
254  // If timer not expired, decrement it
255  Balancer_Active_State[board_num][cell_num] -= (1L << BALANCER_ACTIVE_STATE_TIME_SHIFT);
256 
257  // Look for a new next stop. Note that the maximum does not need to constantly be updated, as the board with the
258  // maximum balance time will remain the max until the end of balancing.
259  balancer_nextstop_update(board_num, bal_timer - 1);
260  }
261  }
262  }
263  }
264  break;
265 
267  // Kick WDT.
268  if(balancer_watchdog_counter == 0)
269  {
271  balancer_watchdog_counter = LTC3300_TWD1 / BALANCER_TASK_RATE;
272  }
273  break;
274  }
275 
276  // Update status bits
277  if(balancer_control_state == BALANCER_CONTROL_OFF)
278  {
279  // If LTC3300 are being allowed to turn off, then their gate drives can not be on.
280  memset(balancer_gate_drive_ok, 0, sizeof(balancer_gate_drive_ok));
281  }
282  else
283  {
284  // In all other states, update the status bits.
285  for (board_num = 0; board_num < System_Num_Boards; board_num++)
286  {
287  balancer_status_update(board_num);
288  }
289  }
290 
291  // Manage passive balancers
292  for (board_num = 0; board_num < System_Num_Boards; board_num++)
293  {
294  LTC6804_Dischargers_Set(board_num, Balancer_Passive_State[board_num], 0);
295  }
296 
297  return;
298 
299 }
300 
301 // Places Balancer Control Task in the BALANCER_CONTROL_SETUP state.
302 // Does not change the active cell balancer states.
303 void Balancer_Set(void)
304 {
305  balancer_control_state = BALANCER_CONTROL_SETUP;
306 
307  return;
308 }
309 
310 // Places Balancer Control Task in the BALANCER_CONTROL_SETUP state.
311 // Loads the desired active cell balancer states.
312 void Balancer_Set(int8 board_num, BALANCER_ACTIVE_STATE_TYPE* cell_state_ptr)
313 {
314  int8 cell_num;
315 
316  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
317  {
318  Balancer_Active_State[board_num][cell_num] = cell_state_ptr[cell_num];
319  balancer_max_and_nextstop_update(board_num, Balancer_Active_State[board_num][cell_num]);
320  }
321 
322  Balancer_Set();
323 
324  return;
325 }
326 
327 // Places Balancer Control Task in the BALANCER_CONTROL_SETUP state.
328 // Calculates and loads the optimal active cell balancer states to achieve the desired amount of charge to move for each cell.
329 // See "CapDemo Balancing Algorithm" worksheet in DC2100A_Deisng.xlsm for a model of this function.
330 // Note - this function is currently only implemented for a single DC2100A board.
331 void Balancer_Set(BALANCER_DELTA_Q_TYPE* charge_target_ptr)
332 {
333  int8 pass_num;
334  int8 board_num;
335  int8 cell_num;
336 
337  signed int32 signed_temp;
338  signed int32 xfr_s_SUM;
339  signed int32 xfr_s_HALFSUM;
340  struct
341  {
342  int16 charge_current; // in mA
343  int16 discharge_current; // in mA
344  signed int32 primary_charge; // in mAs
345  signed int32 total_charge; // in mAs
346  } cell[BALANCER_ALGORITHM_NUM_BOARDS][DC2100A_NUM_CELLS];
347 
348  if(System_Num_Boards == BALANCER_ALGORITHM_NUM_BOARDS)
349  {
350  board_num = DC2100A_PIC_BOARD_NUM;
351 
352  // Initialize variables before iteration.
353  // Balance currents are calibrated values from EEPROM..
354  // Initial guess at primary charge is the value passed into the function.
355  {
356  int16 base_charge_current;
357  int16 base_discharge_current;
358 
359  // Pick the base current, depending upon the model
360  if((System_Model[board_num] == 'A') || (System_Model[board_num] == 'B'))
361  {
362  base_charge_current = BALANCER_AB_CURRENT_CHARGE_6CELL;
363  base_discharge_current = BALANCER_AB_CURRENT_DISCHARGE_6CELL;
364  }
365  else // if((System_Model[board_num] == 'C') || (System_Model[board_num] == 'D'))
366  {
367  base_charge_current = BALANCER_CD_CURRENT_CHARGE_6CELL;
368  base_discharge_current = BALANCER_CD_CURRENT_DISCHARGE_6CELL;
369  }
370 
371  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++) //fill w/ voltages and capacitances for test case
372  {
373  // Store and scale the charge current
374  signed_temp = base_charge_current;
375  signed_temp *= Eeprom_current_values[board_num].current[cell_num].charge;
376  signed_temp = SIGNED_RIGHT_SHIFT_WITH_ROUND(signed_temp, BALANCER_CURRENT_SCALE_FACTOR_SHIFT);
377  cell[board_num][cell_num].charge_current = base_charge_current + signed_temp;
378 
379  // Store and scale the discharge current
380  signed_temp = base_discharge_current;
381  signed_temp *= Eeprom_current_values[board_num].current[cell_num].discharge;
382  signed_temp = SIGNED_RIGHT_SHIFT_WITH_ROUND(signed_temp, BALANCER_CURRENT_SCALE_FACTOR_SHIFT);
383  cell[board_num][cell_num].discharge_current = base_discharge_current + signed_temp;
384 
385  // Scale to time resolution used by balancer algorithm.
386  charge_target_ptr[cell_num] <<= BALANCER_TIME_RESOLUTION_SHIFT;
387 
388  // Start with the primary charge moved equal to the total charge requested to be moved.
389  cell[board_num][cell_num].primary_charge = charge_target_ptr[cell_num];
390  }
391  }
392 
393  // Iterate to find the balancer commands and times that best move the amount of target charge per cell.
394  for (pass_num = 0; pass_num < BALANCER_ALGORITHM_PASSES; pass_num++)
395  {
396  // Calculate the amount of charge moved into the stack by the bottom stack secondary currents.
397  xfr_s_HALFSUM = 0;
398  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS/2; cell_num++)
399  {
400  if(cell[board_num][cell_num].primary_charge >= 0)
401  {
402  signed_temp = cell[board_num][cell_num].primary_charge * BALANCER_DISCHARGE_EFFICIENCY;
403  signed_temp += (DC2100A_NUM_CELLS * PERCENT_MAX) / 2;
404  signed_temp /= (DC2100A_NUM_CELLS * PERCENT_MAX);
405  }
406  else
407  {
408  signed_temp = cell[board_num][cell_num].primary_charge * PERCENT_MAX;
409  signed_temp -= (DC2100A_NUM_CELLS * BALANCER_CHARGE_EFFICIENCY) / 2;
410  signed_temp /= (DC2100A_NUM_CELLS * BALANCER_CHARGE_EFFICIENCY);
411  }
412  xfr_s_HALFSUM += signed_temp;
413  }
414 
415  // Calculate the amount of charge moved into the top of the stack by the top stack secondary currents.
416  xfr_s_SUM = 0;
417  for (cell_num = DC2100A_NUM_CELLS/2; cell_num < DC2100A_NUM_CELLS; cell_num++)
418  {
419  if(cell[board_num][cell_num].primary_charge >= 0)
420  {
421  signed_temp = cell[board_num][cell_num].primary_charge * BALANCER_DISCHARGE_EFFICIENCY;
422  signed_temp += (DC2100A_NUM_CELLS/2 * PERCENT_MAX) / 2;
423  signed_temp /= (DC2100A_NUM_CELLS/2 * PERCENT_MAX);
424  }
425  else
426  {
427  signed_temp = cell[board_num][cell_num].primary_charge * PERCENT_MAX;
428  signed_temp -= (DC2100A_NUM_CELLS/2 * BALANCER_CHARGE_EFFICIENCY) / 2;
429  signed_temp /= (DC2100A_NUM_CELLS/2 * BALANCER_CHARGE_EFFICIENCY);
430  }
431  xfr_s_SUM += signed_temp;
432  }
433 
434  // Calculate the total amount of charge moved (primary and secondary currents)
435  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++) //new voltage computation
436  {
437  cell[board_num][cell_num].total_charge = cell[board_num][cell_num].primary_charge - xfr_s_HALFSUM;
438 
439  if(cell_num >= DC2100A_NUM_CELLS/2)
440  {
441  cell[board_num][cell_num].total_charge -= xfr_s_SUM;
442  }
443  }
444 
445  // Calculate the average discrepancy between the charge requested to be moved into the bottom of the stack and charge that actually was.
446  xfr_s_HALFSUM = 0;
447  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS/2; cell_num++)
448  {
449  xfr_s_HALFSUM += charge_target_ptr[cell_num] - cell[board_num][cell_num].total_charge;
450  }
451  xfr_s_HALFSUM = SIGNED_DIVIDE_BY_UNSIGNED_WITH_ROUND(xfr_s_HALFSUM, DC2100A_NUM_CELLS/2);
452 
453  // Calculate the average discrepancy between the charge requested to be moved into the top of the stack and charge that actually was.
454  xfr_s_SUM = 0;
455  for (cell_num = DC2100A_NUM_CELLS/2; cell_num < DC2100A_NUM_CELLS; cell_num++)
456  {
457  xfr_s_SUM += charge_target_ptr[cell_num] - cell[board_num][cell_num].total_charge;
458  }
459  xfr_s_SUM = SIGNED_DIVIDE_BY_UNSIGNED_WITH_ROUND(xfr_s_SUM, DC2100A_NUM_CELLS/2);
460 
461  // Calculate next guess for primary currents
462  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++) //new voltage computation
463  {
464  signed int32 cell_charge_feedback_term;
465  signed int32 half_stack_charge_feedback_term;
466 
467  // Calculate feedback term for cell charge moved.
468  cell_charge_feedback_term = charge_target_ptr[cell_num] - cell[board_num][cell_num].total_charge;
469  cell_charge_feedback_term -= SIGNED_RIGHT_SHIFT_WITH_ROUND(xfr_s_HALFSUM + xfr_s_SUM, 1); // average losses over all cells
470  cell_charge_feedback_term = SIGNED_RIGHT_SHIFT_WITH_ROUND(cell_charge_feedback_term, BALANCER_CELL_CHARGE_ERROR_DAMPING_SHIFT);
471 
472  // Calculate feedback term for balancing half stacks.
473  if(cell_num < DC2100A_NUM_CELLS/2)
474  {
475  half_stack_charge_feedback_term = (xfr_s_HALFSUM - xfr_s_SUM);
476  half_stack_charge_feedback_term = SIGNED_RIGHT_SHIFT_WITH_ROUND(half_stack_charge_feedback_term, BALANCER_HALF_STACK_EEROR_DAMPING_SHIFT);
477  }
478  else
479  {
480  // Cells in the top half stack can only move charge within their own half stack.
481  half_stack_charge_feedback_term = 0;
482  }
483 
484  // Calculate next guess at primary charge using feedback terms.
485  cell[board_num][cell_num].primary_charge += cell_charge_feedback_term;
486  cell[board_num][cell_num].primary_charge += half_stack_charge_feedback_term;
487  }
488  }
489 
490  // Build balancer command with times and directions.
491  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++) //compute total adjusted times (difference between net chg/dchg times)
492  {
493  if(cell[board_num][cell_num].primary_charge >= 0)
494  {
495  signed_temp = cell[board_num][cell_num].primary_charge;
496  signed_temp += (cell[board_num][cell_num].discharge_current >> 1);
497  signed_temp /= cell[board_num][cell_num].discharge_current;
498  Balancer_Active_State[board_num][cell_num] = signed_temp;
499  if(signed_temp != 0 )
500  {
501  Balancer_Active_State[board_num][cell_num] |= BALANCER_ACTIVE_STATE_COMMAND_MASK; // Set bit to indicate discharging
502  }
503  else
504  {
505  Balancer_Active_State[board_num][cell_num] &= ~BALANCER_ACTIVE_STATE_COMMAND_MASK; // Clear bit to indicate charging (or None)
506  }
507 
508  // Calculate actual charge moved and scale back to mAs for SOC algorithm.
509  //signed_temp = (signed_temp) * cell[board_num][cell_num].discharge_current; // todo - the xls feeds back the theoretical Delta-Q, not what actually is actually moved due to the quantitized balancer times.
510  signed_temp = cell[board_num][cell_num].total_charge;
511  charge_target_ptr[cell_num] = SIGNED_RIGHT_SHIFT_WITH_ROUND(signed_temp, BALANCER_TIME_RESOLUTION_SHIFT);
512  }
513  else
514  {
515  signed_temp = -cell[board_num][cell_num].primary_charge;
516  signed_temp += (cell[board_num][cell_num].charge_current >> 1);
517  signed_temp /= cell[board_num][cell_num].charge_current;
518  Balancer_Active_State[board_num][cell_num] = signed_temp;
519  Balancer_Active_State[board_num][cell_num] &= ~BALANCER_ACTIVE_STATE_COMMAND_MASK; // Clear bit to indicate charging (or None)
520 
521  // Calculate actual charge moved and scale back to mAs for SOC algorithm.
522  //signed_temp = (-signed_temp) * cell[board_num][cell_num].charge_current; // todo - the xls feeds back the theoretical Delta-Q, not what actually is actually moved due to the quantitized balancer times.
523  signed_temp = cell[board_num][cell_num].total_charge;
524  charge_target_ptr[cell_num] = SIGNED_RIGHT_SHIFT_WITH_ROUND(signed_temp, BALANCER_TIME_RESOLUTION_SHIFT);
525  }
526 
527  balancer_max_and_nextstop_update(board_num, Balancer_Active_State[board_num][cell_num]);
528  }
529 
530  }
531 
532  Balancer_Set();
533 
534  return;
535 }
536 
537 // Places Balancer Control Task in the BALANCER_CONTROL_ON state. Note that balancing is not started until the next state execution,
538 // to ensure that the balance times are accurately controlled to the BALANCER_TASK_RATE resolution.
539 void Balancer_Start(void)
540 {
541  balancer_watchdog_counter = 0;
542  balancer_control_state = BALANCER_CONTROL_ON;
543 }
544 
545 // Places Balancer Control Task in the BALANCER_CONTROL_OFF state immediately, as it's possible there's a catastrophic reason why we,
546 // need to suspend,and resets the Balancer Control Task.
547 void Balancer_Stop(void)
548 {
549  memset(Balancer_Active_State, 0, sizeof(Balancer_Active_State));
550 
555 
557  balancer_control_state = BALANCER_CONTROL_OFF;
558 }
559 
560 // Places Balancer Control Task in the BALANCER_CONTROL_SUSPEND state immediately as it's possible there's a catastrophic reason why we
561 // need to suspend.
563 {
565  balancer_control_state = BALANCER_CONTROL_SUSPEND;
566 }
567 
568 // Places Balancer Control Task in the BALANCER_CONTROL_GUI state, stopping all control of balancers by Balancer Control Task,
569 // and allows full control of LTC3300 ICs through direct commands from GUI.
570 void Balancer_GUI(void)
571 {
572  balancer_control_state = BALANCER_CONTROL_GUI;
573 }
574 
575 // Returns if any balancer is actively balancing.
577 {
578  int8 board_num;
579 
580  for (board_num = 0; board_num < System_Num_Boards; board_num++)
581  {
582  if(balancer_gate_drive_ok[board_num] != 0)
583  {
584  return TRUE;
585  }
586  }
587 
588  return FALSE;
589 }
590 
591 // Sets Balancer Control Task for synchronous or asynchronous mode.
592 void Balancer_Synchronous_Mode_Set(BOOLEAN synchronous_mode)
593 {
594  balancer_synchronous_mode = synchronous_mode;
595 }
596 
597 // Returns if Balancer Control Task is configured for synchronous mode.
599 {
600  return balancer_synchronous_mode;
601 }
602 
603 // Forces recalculation of the longest and shortest (yet non-zero) active balance times in the DC2100A system.
605 {
606  int8 board_num;
607  int8 cell_num;
608 
609  // Reset the Max and Nextstop, then search through all boards to find the new Max and Nextstop
612 
613  for (board_num = 0; board_num < System_Num_Boards; board_num++)
614  {
615  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
616  {
617  balancer_max_and_nextstop_update(board_num, Balancer_Active_State[board_num][cell_num]);
618  }
619  }
620 
621  return;
622 }
623 
624 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
625 // Local Functions
626 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
627 
628 // Sends a balancer command to the LTC3300s
629 void balancer_command_update(int8 board_num)
630 {
631  int8 cell_num;
632  int8 charge_code;
633  int8 discharge_code;
634  int8 balancer_command_write[DC2100A_NUM_CELLS];
635  int8 balancer_command_read[DC2100A_NUM_CELLS];
636  BOOLEAN write_success;
637 
638  // Use the appropriate codes, depending upon whether set for synchronous or non-synchronous mode
639  if(balancer_synchronous_mode == TRUE)
640  {
643  }
644  else
645  {
648  }
649 
650  // Loop through cells to convert timer values and balance directions into LTC3300 balancer control codes.
651  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
652  {
653  if((Balancer_Active_State[board_num][cell_num] & BALANCER_ACTIVE_STATE_TIME_MASK) == 0)
654  {
655  // If timer has expired, then turn balancer off
656  balancer_command_write[cell_num] = LTC3300_BALANCER_CONTROL_CODE_NONE;
657  }
658  else
659  {
661  {
662  // If discharging, use appropriate discharge code
663  balancer_command_write[cell_num] = discharge_code;
664  }
665  else
666  {
667  // If charging, use appropriate charge code
668  balancer_command_write[cell_num] = charge_code;
669  }
670  }
671  }
672 
673  // Write the balance command to the LTC3300s for this board
674  LTC3300_Command_Write(board_num, balancer_command_write);
675 
676  // Read the balance command to the LTC3300s for this board
677  if( LTC3300_Command_Read(board_num, balancer_command_read) == TRUE)
678  {
679  // Check if the write was successful
680  write_success = TRUE; // Start by assuming the write was successful
681  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
682  {
683  if(balancer_command_write[cell_num] != balancer_command_read[cell_num])
684  {
685  write_success = FALSE; // Start by assuming the write was successful
686  break;
687  }
688  }
689 
690  // If the write wasn't successful, create an error log entry
691  if(write_success != TRUE)
692  {
693  int8 temp_data[ERROR_DATA_SIZE];
694  memset(temp_data, 0, sizeof(temp_data));
695  temp_data[0] = board_num;
696 
697  // Build a bitmap of the written and read balancer commands
698  for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
699  {
700  *((int32*)(temp_data + 1)) |= ((int32)balancer_command_write[cell_num] << (cell_num * NBITS(LTC3300_BALANCER_NUM_CONTROL_CODES - 1)));
701  *((int32*)(temp_data + 4)) |= ((int32)balancer_command_read[cell_num] << (cell_num * NBITS(LTC3300_BALANCER_NUM_CONTROL_CODES - 1)));
702  }
703  Error_Data_Set(ERROR_CODE_LTC3300_FAILED_CMD_WRITE, temp_data, sizeof(temp_data));
704  }
705  }
706 
707  return;
708 }
709 
710 // Updates the longest and shortest (yet non-zero) active balance times and board numbers, if the active balancer state argument is the longest or
711 // shortest (yet non-zero) active balance time.
712 void balancer_max_and_nextstop_update(int8 board_num, BALANCER_ACTIVE_STATE_TYPE balancer_state)
713 {
714  int16 bal_timer;
715 
716  bal_timer = balancer_state & BALANCER_ACTIVE_STATE_TIME_MASK;
717  if(bal_timer > Balancer_Active_Time_Max)
718  {
719  Balancer_Active_Time_Max = bal_timer;
720  Balancer_Active_Board_Max = board_num;
721  }
722 
723  if(bal_timer != 0)
724  {
725  balancer_nextstop_update(board_num, bal_timer);
726  }
727 
728  return;
729 }
730 
731 // Updates the shortest (yet non-zero) active balance time and board number, if the bal_timer argument is the shortest (yet non-zero) active balance time.
732 void balancer_nextstop_update(int8 board_num, int16 bal_timer)
733 {
735  {
736  Balancer_Active_Time_Next_Stop = bal_timer;
738  }
739 
740  return;
741 }
742 
743 // Updates the status bits for the balancers on one board.
744 void balancer_status_update(int8 board_num)
745 {
746  int8 bal_num;
747  int8 gate_drive_ok[DC2100A_NUM_LTC3300];
748  int8 cells_ov_ok[DC2100A_NUM_LTC3300];
749  int8 stack_ov_ok[DC2100A_NUM_LTC3300];
750  int8 temp_ok[DC2100A_NUM_LTC3300];
751 
752  // Get the data for this board
753  if(LTC3300_Status_Read(DC2100A_PIC_BOARD_NUM, gate_drive_ok, cells_ov_ok, stack_ov_ok, temp_ok) == TRUE)
754  {
755 
756  // Store data retrieved from LTC3300.
757 
758  // Init status bits to be ok, and then clear if any of the bits are not ok for this board.
759  balancer_cells_ov_ok |= MASK(1, board_num);
760  balancer_stack_ov_ok |= MASK(1, board_num);
761  balancer_temperature_ok |= MASK(1, board_num);
762 
763  // Init gate drive bits to be not ok, as that also means off.
764  balancer_gate_drive_ok[board_num] = 0;
765 
766  for (bal_num = 0; bal_num < DC2100A_NUM_LTC3300; bal_num++)
767  {
768  balancer_gate_drive_ok[board_num] |= ((unsigned int16) gate_drive_ok[bal_num] << (LTC3300_NUM_CELLS * bal_num));
769  if(cells_ov_ok[bal_num])
770  balancer_cells_ov_ok &= ~MASK(1, board_num);
771  if(cells_ov_ok[bal_num])
772  balancer_stack_ov_ok &= ~MASK(1, board_num);
773  if(cells_ov_ok[bal_num])
774  balancer_temperature_ok &= ~MASK(1, board_num);
775  }
776  }
777  return;
778 }
void Balancer_GUI(void)
Places Balancer Control Task in the BALANCER_CONTROL_GUI state, stopping all control of balancers by ...
Definition: Balancer.c:570
EEPROM_CURRENT_TYPE Eeprom_current_values[DC2100A_MAX_BOARDS]
Copy of balance currents values allows quick balance calculations.
Definition: EEPROM.c:123
void Balancer_Set(void)
Places Balancer Control Task in the BALANCER_CONTROL_SETUP state.
Definition: Balancer.c:303
void LTC3300_Execute(int8 board_num)
Commands a chain of LTC3300s at a specific logical address to execute their balance commands...
Definition: LTC3300-1.c:320
void Balancer_Max_and_Nextstop_Find(void)
Forces recalculation of the longest and shortest (yet non-zero) active balance times in the DC2100A s...
Definition: Balancer.c:604
#define LTC3300_NUM_CELLS
Number of cells controlled by one LTC3300.
Definition: LTC3300-1.h:85
#define LTC3300_BALANCER_CONTROL_CODE_CHARGE
Balancing Action: Charge Cell n.
Definition: LTC3300-1.h:98
struct EEPROM_CURRENT_TYPE::@0 current[DC2100A_NUM_CELLS]
current calibration factor in BALANCER_CURRENT_SCALE units
int8 Balancer_Active_Board_Max
The board with the longest remaining balance time.
Definition: Balancer.c:92
int16 BALANCER_PASSIVE_STATE_TYPE
Bitmap for LTC6804_NUM_CELLV_ADC passive balancers on one DC2100A, 1 = ON and 0 = Off...
Definition: Balancer.h:105
void Balancer_Suspend(void)
Places Balancer Control Task in the BALANCER_CONTROL_SUSPEND state immediately as it's possible there...
Definition: Balancer.c:562
void Balancer_Start(void)
Places Balancer Control Task in the BALANCER_CONTROL_ON state.
Definition: Balancer.c:539
#define LTC6804_BROADCAST
Code for application code to indicate an LTC6804 command is to be broadcast to all boards...
Definition: LTC6804-2.h:89
void LTC6804_Dischargers_Set(int8 board_num, int16 discharge_bitmap, int16 timeout_value)
Sets the LTC6804 discharger pin levels and timeout values.
Definition: LTC6804-2.c:256
BOOLEAN Balancer_Is_Balancing(void)
Returns if any balancer is actively balancing.
Definition: Balancer.c:576
#define BALANCER_ACTIVE_STATE_TIME_SHIFT
Position of bit field used to hold time to balance.
Definition: Balancer.h:96
Reference Application File for EEPROM Data specific to the LTC6804-2 Battery Monitor on the DC2100A P...
#define LTC3300_BALANCER_CONTROL_CODE_DISCHARGE_SYNC
Balancing Action: Discharge Cell n (Synchronous)
Definition: LTC3300-1.h:97
void Balancer_Synchronous_Mode_Set(BOOLEAN synchronous_mode)
Sets Balancer Control Task for synchronous or asynchronous mode.
Definition: Balancer.c:592
BALANCER_ACTIVE_STATE_TYPE Balancer_Active_State[DC2100A_MAX_BOARDS][DC2100A_NUM_CELLS]
The state of each active cell balancer on each DC2100A in the system.
Definition: Balancer.c:89
#define LTC3300_BALANCER_CONTROL_CODE_DISCHARGE_NONSYNC
Balancing Action: Discharge Cell n (Nonsynchronous)
Definition: LTC3300-1.h:96
Balancing is not active.
Definition: Balancer.h:72
Balancing commands are suspended.
Definition: Balancer.h:76
#define LTC3300_TWD1
in ms, min Watchdog Timer Timeout Period WDT Assertion Measured from Last Valid Command Byte (from da...
Definition: LTC3300-1.h:86
BOOLEAN Balancer_Synchronous_Mode_Get(void)
Returns if Balancer Control Task is configured for synchronous mode.
Definition: Balancer.c:598
API Header File for LTC6804-2 Multicell Battery Monitors.
void LTC3300_Command_Write(int8 board_num, int8 *balancer_command_ptr)
Writes the balancer control bits for a number of cells controlled by a chain of LTC3300-1 ICs at a sp...
Definition: LTC3300-1.c:151
#define BALANCER_CD_CURRENT_CHARGE_6CELL
in mA, nominal charge balance current for cells with 6 cell secondary connections on a DC2100A-C or D...
Definition: Balancer.h:123
void LTC3300_Suspend(int8 board_num)
Commands a chain of LTC3300s at a specific logical address to suspend their balance commands...
Definition: LTC3300-1.c:335
signed int8 charge
charge current calibration factor
Definition: EEPROM.h:85
int16 BALANCER_ACTIVE_STATE_TYPE
Size of structure used for balancer active state.
Definition: Balancer.h:91
BOOLEAN Balancer_Wakeup_Init(void)
Initializes the parts of the Balancer Module, that need to be initialized upon wakeup of the LTC3300-...
Definition: Balancer.c:143
Balancing commands are being executed for a timed value for each cell.
Definition: Balancer.h:75
#define LTC3300_BALANCER_CONTROL_CODE_NONE
Balancing Action: None.
Definition: LTC3300-1.h:95
int8 Balancer_Active_Board_Next_Stop
The cell with the shortest, yet non-zero, remaining balance time.
Definition: Balancer.c:93
API Header File for LTC3300-1 High Efficiency Bidirectional Multicell Battery Balancer.
#define BALANCER_AB_CURRENT_DISCHARGE_6CELL
in mA, nominal discharge balance current for cells with 6 cell secondary connections on a DC2100A-A o...
Definition: Balancer.h:120
void LTC3300_Watchdog_Kick(void)
Sends a benign command to all chains of LTC3300s at all logical addresses to reset their watchdog tim...
Definition: LTC3300-1.c:350
#define BALANCER_CURRENT_SCALE_FACTOR_SHIFT
number of bits to shift for equivalant of division by BALANCER_CURRENT_SCALE_FACTOR ...
Definition: Balancer.h:126
BALANCER_PASSIVE_STATE_TYPE Balancer_Passive_State[DC2100A_MAX_BOARDS]
Bitmap for LTC6804_NUM_CELLV_ADC passive balancers on one DC2100A, 1 = ON and 0 = Off...
Definition: Balancer.c:94
#define BALANCER_AB_CURRENT_CHARGE_6CELL
in mA, nominal charge balance current for cells with 6 cell secondary connections on a DC2100A-A or D...
Definition: Balancer.h:119
BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Next_Stop
The shortest, yet non-zero, active balance time in the DC2100A system.
Definition: Balancer.c:91
signed int8 discharge
discharge current calibration factor
Definition: EEPROM.h:86
BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Max
The longest active balance time in the DC2100A system.
Definition: Balancer.c:90
BOOLEAN LTC3300_Command_Read(int8 board_num, int8 *balancer_command_ptr)
Reads the balancer control bits for a number of cells controlled by a chain of LTC3300-1 ICs at a spe...
Definition: LTC3300-1.c:194
Watchdog is being activated to prevent LTC3300s from going to sleep, but raw commands are being sent ...
Definition: Balancer.h:73
BALANCER_CONTROL_STATE_TYPE
Definition: Balancer.h:70
BOOLEAN LTC3300_Status_Read(int8 board_num, int8 *gate_drive_ok, int8 *cells_ov_ok, int8 *stack_ov_ok, int8 *temp_ok)
Reads the status bits for a chain of LTC3300-1 ICs at a specific logical address. ...
Definition: LTC3300-1.c:253
void Balancer_Control_Task(void)
Executes the Balancer Control task.
Definition: Balancer.c:168
Balancing commands are being loaded.
Definition: Balancer.h:74
void Balancer_Stop(void)
Places Balancer Control Task in the BALANCER_CONTROL_OFF state immediately, as it's possible there's ...
Definition: Balancer.c:547
signed int32 BALANCER_DELTA_Q_TYPE
Data Type for amount of charge to move from a cell in mAs.
Definition: Balancer.h:110
void Balancer_Init(void)
Initializes the parts of the Balancer Module, that need to be initialized upon power-up of the PIC...
Definition: Balancer.c:120
#define LTC3300_BALANCER_NUM_CONTROL_CODES
Number of Balancing Actions.
Definition: LTC3300-1.h:99
#define BALANCER_ACTIVE_STATE_COMMAND_MASK
Mask for bit field used to indicate charge and discharge.
Definition: Balancer.h:94
Reference Application File for Controlling the LTC3300-1 Battery Balancers through the LTC6804-2 Batt...
#define BALANCER_CD_CURRENT_DISCHARGE_6CELL
in mA, nominal discharge balance current for cells with 6 cell secondary connections on a DC2100A-C o...
Definition: Balancer.h:124
#define BALANCER_TASK_RATE
in ms, the rate at which the balancer control task is executed.
Definition: Balancer.h:64
#define BALANCER_ACTIVE_STATE_TIME_MASK
Mask for bit field used to hold time to balance.
Definition: Balancer.h:97