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.
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.
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)
100 int8 balancer_watchdog_counter;
101 BOOLEAN balancer_synchronous_mode;
102 unsigned int16 balancer_gate_drive_ok[DC2100A_MAX_BOARDS];
103 unsigned int16 balancer_cells_ov_ok;
104 unsigned int16 balancer_stack_ov_ok;
105 unsigned int16 balancer_temperature_ok;
110 void balancer_command_update(int8 board_num);
111 void balancer_nextstop_update(int8 board_num, int16 bal_timer);
113 void balancer_status_update(int8 board_num);
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;
138 balancer_synchronous_mode = TRUE;
145 BOOLEAN success = TRUE;
147 int8 balancer_command[DC2100A_NUM_CELLS];
150 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
175 if(balancer_watchdog_counter != 0)
177 balancer_watchdog_counter--;
180 switch (balancer_control_state)
190 if(balancer_watchdog_counter == 0)
199 if(balancer_watchdog_counter == 0)
205 for (board_num = 0; board_num < System_Num_Boards; board_num++)
208 balancer_command_update(board_num);
216 for (board_num = 0; board_num < System_Num_Boards; board_num++)
218 balancer_command_update(board_num);
241 for (board_num = 0; board_num < System_Num_Boards; board_num++)
244 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
259 balancer_nextstop_update(board_num, bal_timer - 1);
268 if(balancer_watchdog_counter == 0)
280 memset(balancer_gate_drive_ok, 0,
sizeof(balancer_gate_drive_ok));
285 for (board_num = 0; board_num < System_Num_Boards; board_num++)
287 balancer_status_update(board_num);
292 for (board_num = 0; board_num < System_Num_Boards; board_num++)
316 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
337 signed int32 signed_temp;
338 signed int32 xfr_s_SUM;
339 signed int32 xfr_s_HALFSUM;
342 int16 charge_current;
343 int16 discharge_current;
344 signed int32 primary_charge;
345 signed int32 total_charge;
346 } cell[BALANCER_ALGORITHM_NUM_BOARDS][DC2100A_NUM_CELLS];
348 if(System_Num_Boards == BALANCER_ALGORITHM_NUM_BOARDS)
350 board_num = DC2100A_PIC_BOARD_NUM;
356 int16 base_charge_current;
357 int16 base_discharge_current;
360 if((System_Model[board_num] ==
'A') || (System_Model[board_num] ==
'B'))
371 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
374 signed_temp = base_charge_current;
377 cell[board_num][cell_num].charge_current = base_charge_current + signed_temp;
380 signed_temp = base_discharge_current;
383 cell[board_num][cell_num].discharge_current = base_discharge_current + signed_temp;
386 charge_target_ptr[cell_num] <<= BALANCER_TIME_RESOLUTION_SHIFT;
389 cell[board_num][cell_num].primary_charge = charge_target_ptr[cell_num];
394 for (pass_num = 0; pass_num < BALANCER_ALGORITHM_PASSES; pass_num++)
398 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS/2; cell_num++)
400 if(cell[board_num][cell_num].primary_charge >= 0)
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);
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);
412 xfr_s_HALFSUM += signed_temp;
417 for (cell_num = DC2100A_NUM_CELLS/2; cell_num < DC2100A_NUM_CELLS; cell_num++)
419 if(cell[board_num][cell_num].primary_charge >= 0)
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);
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);
431 xfr_s_SUM += signed_temp;
435 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
437 cell[board_num][cell_num].total_charge = cell[board_num][cell_num].primary_charge - xfr_s_HALFSUM;
439 if(cell_num >= DC2100A_NUM_CELLS/2)
441 cell[board_num][cell_num].total_charge -= xfr_s_SUM;
447 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS/2; cell_num++)
449 xfr_s_HALFSUM += charge_target_ptr[cell_num] - cell[board_num][cell_num].total_charge;
451 xfr_s_HALFSUM = SIGNED_DIVIDE_BY_UNSIGNED_WITH_ROUND(xfr_s_HALFSUM, DC2100A_NUM_CELLS/2);
455 for (cell_num = DC2100A_NUM_CELLS/2; cell_num < DC2100A_NUM_CELLS; cell_num++)
457 xfr_s_SUM += charge_target_ptr[cell_num] - cell[board_num][cell_num].total_charge;
459 xfr_s_SUM = SIGNED_DIVIDE_BY_UNSIGNED_WITH_ROUND(xfr_s_SUM, DC2100A_NUM_CELLS/2);
462 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
464 signed int32 cell_charge_feedback_term;
465 signed int32 half_stack_charge_feedback_term;
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);
470 cell_charge_feedback_term = SIGNED_RIGHT_SHIFT_WITH_ROUND(cell_charge_feedback_term, BALANCER_CELL_CHARGE_ERROR_DAMPING_SHIFT);
473 if(cell_num < DC2100A_NUM_CELLS/2)
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);
481 half_stack_charge_feedback_term = 0;
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;
491 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
493 if(cell[board_num][cell_num].primary_charge >= 0)
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;
499 if(signed_temp != 0 )
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);
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;
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);
541 balancer_watchdog_counter = 0;
580 for (board_num = 0; board_num < System_Num_Boards; board_num++)
582 if(balancer_gate_drive_ok[board_num] != 0)
594 balancer_synchronous_mode = synchronous_mode;
600 return balancer_synchronous_mode;
613 for (board_num = 0; board_num < System_Num_Boards; board_num++)
615 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
629 void balancer_command_update(int8 board_num)
634 int8 balancer_command_write[DC2100A_NUM_CELLS];
635 int8 balancer_command_read[DC2100A_NUM_CELLS];
636 BOOLEAN write_success;
639 if(balancer_synchronous_mode == TRUE)
651 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
663 balancer_command_write[cell_num] = discharge_code;
668 balancer_command_write[cell_num] = charge_code;
680 write_success = TRUE;
681 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
683 if(balancer_command_write[cell_num] != balancer_command_read[cell_num])
685 write_success = FALSE;
691 if(write_success != TRUE)
693 int8 temp_data[ERROR_DATA_SIZE];
694 memset(temp_data, 0,
sizeof(temp_data));
695 temp_data[0] = board_num;
698 for (cell_num = 0; cell_num < DC2100A_NUM_CELLS; cell_num++)
703 Error_Data_Set(ERROR_CODE_LTC3300_FAILED_CMD_WRITE, temp_data,
sizeof(temp_data));
725 balancer_nextstop_update(board_num, bal_timer);
732 void balancer_nextstop_update(int8 board_num, int16 bal_timer)
744 void balancer_status_update(int8 board_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];
753 if(
LTC3300_Status_Read(DC2100A_PIC_BOARD_NUM, gate_drive_ok, cells_ov_ok, stack_ov_ok, temp_ok) == TRUE)
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);
764 balancer_gate_drive_ok[board_num] = 0;
766 for (bal_num = 0; bal_num < DC2100A_NUM_LTC3300; bal_num++)
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);
void Balancer_GUI(void)
Places Balancer Control Task in the BALANCER_CONTROL_GUI state, stopping all control of balancers by ...
EEPROM_CURRENT_TYPE Eeprom_current_values[DC2100A_MAX_BOARDS]
Copy of balance currents values allows quick balance calculations.
void Balancer_Set(void)
Places Balancer Control Task in the BALANCER_CONTROL_SETUP state.
void LTC3300_Execute(int8 board_num)
Commands a chain of LTC3300s at a specific logical address to execute their balance commands...
void Balancer_Max_and_Nextstop_Find(void)
Forces recalculation of the longest and shortest (yet non-zero) active balance times in the DC2100A s...
#define LTC3300_NUM_CELLS
Number of cells controlled by one LTC3300.
#define LTC3300_BALANCER_CONTROL_CODE_CHARGE
Balancing Action: Charge Cell n.
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.
int16 BALANCER_PASSIVE_STATE_TYPE
Bitmap for LTC6804_NUM_CELLV_ADC passive balancers on one DC2100A, 1 = ON and 0 = Off...
void Balancer_Suspend(void)
Places Balancer Control Task in the BALANCER_CONTROL_SUSPEND state immediately as it's possible there...
void Balancer_Start(void)
Places Balancer Control Task in the BALANCER_CONTROL_ON state.
#define LTC6804_BROADCAST
Code for application code to indicate an LTC6804 command is to be broadcast to all boards...
void LTC6804_Dischargers_Set(int8 board_num, int16 discharge_bitmap, int16 timeout_value)
Sets the LTC6804 discharger pin levels and timeout values.
BOOLEAN Balancer_Is_Balancing(void)
Returns if any balancer is actively balancing.
#define BALANCER_ACTIVE_STATE_TIME_SHIFT
Position of bit field used to hold time to balance.
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)
void Balancer_Synchronous_Mode_Set(BOOLEAN synchronous_mode)
Sets Balancer Control Task for synchronous or asynchronous mode.
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.
#define LTC3300_BALANCER_CONTROL_CODE_DISCHARGE_NONSYNC
Balancing Action: Discharge Cell n (Nonsynchronous)
Balancing commands are suspended.
#define LTC3300_TWD1
in ms, min Watchdog Timer Timeout Period WDT Assertion Measured from Last Valid Command Byte (from da...
BOOLEAN Balancer_Synchronous_Mode_Get(void)
Returns if Balancer Control Task is configured for synchronous mode.
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...
#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...
void LTC3300_Suspend(int8 board_num)
Commands a chain of LTC3300s at a specific logical address to suspend their balance commands...
signed int8 charge
charge current calibration factor
int16 BALANCER_ACTIVE_STATE_TYPE
Size of structure used for balancer active state.
BOOLEAN Balancer_Wakeup_Init(void)
Initializes the parts of the Balancer Module, that need to be initialized upon wakeup of the LTC3300-...
Balancing commands are being executed for a timed value for each cell.
#define LTC3300_BALANCER_CONTROL_CODE_NONE
Balancing Action: None.
int8 Balancer_Active_Board_Next_Stop
The cell with the shortest, yet non-zero, remaining balance time.
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...
void LTC3300_Watchdog_Kick(void)
Sends a benign command to all chains of LTC3300s at all logical addresses to reset their watchdog tim...
#define BALANCER_CURRENT_SCALE_FACTOR_SHIFT
number of bits to shift for equivalant of division by BALANCER_CURRENT_SCALE_FACTOR ...
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...
#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...
BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Next_Stop
The shortest, yet non-zero, active balance time in the DC2100A system.
signed int8 discharge
discharge current calibration factor
BALANCER_ACTIVE_STATE_TYPE Balancer_Active_Time_Max
The longest active balance time in the DC2100A system.
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...
Watchdog is being activated to prevent LTC3300s from going to sleep, but raw commands are being sent ...
BALANCER_CONTROL_STATE_TYPE
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. ...
void Balancer_Control_Task(void)
Executes the Balancer Control task.
Balancing commands are being loaded.
void Balancer_Stop(void)
Places Balancer Control Task in the BALANCER_CONTROL_OFF state immediately, as it's possible there's ...
signed int32 BALANCER_DELTA_Q_TYPE
Data Type for amount of charge to move from a cell in mAs.
void Balancer_Init(void)
Initializes the parts of the Balancer Module, that need to be initialized upon power-up of the PIC...
#define LTC3300_BALANCER_NUM_CONTROL_CODES
Number of Balancing Actions.
#define BALANCER_ACTIVE_STATE_COMMAND_MASK
Mask for bit field used to indicate charge and discharge.
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...
#define BALANCER_TASK_RATE
in ms, the rate at which the balancer control task is executed.
#define BALANCER_ACTIVE_STATE_TIME_MASK
Mask for bit field used to hold time to balance.