Balancing Module Sources¶
bal.c¶
/**
*
* @copyright © 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file bal.c
* @author foxBMS Team
* @date 26.02.2016 (date of creation)
* @ingroup DRIVERS
* @prefix BAL
*
* @brief Driver for the Balancing module
*
*/
/*================== Includes =============================================*/
#include "bal.h"
#include "batterycell_cfg.h"
#include "database.h"
#include "FreeRTOS.h"
#include "sox.h"
#include "task.h"
/*================== Macros and Definitions ===============================*/
/**
* Saves the last state and the last substate
*/
#define BAL_SAVELASTSTATES() bal_state.laststate = bal_state.state; \
bal_state.lastsubstate = bal_state.substate
/*================== Constant and Variable Definitions ====================*/
static DATA_BLOCK_MINMAX_s bal_minmax;
static DATA_BLOCK_BALANCING_CONTROL_s bal_balancing;
static DATA_BLOCK_CELLVOLTAGE_s bal_cellvoltage;
DATA_BLOCK_STATEREQUEST_s bal_request;
/**
* contains the state of the contactor state machine
*
*/
static BAL_STATE_s bal_state = {
.timer = 0,
.statereq = BAL_STATE_NO_REQUEST,
.state = BAL_STATEMACH_UNINITIALIZED,
.substate = BAL_ENTRY,
.laststate = BAL_STATEMACH_UNINITIALIZED,
.lastsubstate = 0,
.triggerentry = 0,
.ErrRequestCounter = 0,
.initFinished = E_NOT_OK,
.active = FALSE,
.resting = TRUE,
.rest_timer = BAL_TIME_BEFORE_BALANCING_S*10,
.balancing_threshold = BAL_THRESHOLD_MV + BAL_HYSTERESIS_MV,
.balancing_allowed = TRUE,
.balancing_global_allowed = FALSE,
};
/*================== Function Prototypes ==================================*/
static BAL_RETURN_TYPE_e BAL_CheckStateRequest(BAL_STATE_REQUEST_e statereq);
static BAL_STATE_REQUEST_e BAL_GetStateRequest(void);
static BAL_STATE_REQUEST_e BAL_TransferStateRequest(void);
static uint8_t BAL_CheckReEntrance(void);
static void BAL_Init(void);
static void BAL_Deactivate(void);
#if BALANCING_VOLTAGE_BASED == TRUE
static uint8_t BAL_Activate_Balancing_Voltage(void);
#else
static uint8_t BAL_Check_Imbalances(void);
static void BAL_Compute_Imbalances(void);
static void BAL_Activate_Balancing_History(void);
#endif
/*================== Function Implementations =============================*/
static void BAL_Init(void) {
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
bal_balancing.enable_balancing = 0;
DB_WriteBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
}
static void BAL_Deactivate(void) {
uint16_t i;
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
bal_balancing.balancing_state[i] = 0;
bal_balancing.delta_charge[i] = 0;
}
bal_balancing.enable_balancing = 0;
bal_state.active = FALSE;
bal_balancing.previous_timestamp = bal_balancing.timestamp;
bal_balancing.timestamp = OS_getOSSysTick();
DB_WriteBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
}
#if BALANCING_VOLTAGE_BASED == TRUE
static uint8_t BAL_Activate_Balancing_Voltage(void) {
uint32_t i = 0;
uint16_t min = 0;
uint8_t finished = TRUE;
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
DB_ReadBlock(&bal_cellvoltage, DATA_BLOCK_ID_CELLVOLTAGE);
DB_ReadBlock(&bal_minmax, DATA_BLOCK_ID_MINMAX);
min = bal_minmax.voltage_min;
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
if (bal_cellvoltage.voltage[i] > min+bal_state.balancing_threshold) {
bal_balancing.balancing_state[i] = 1;
finished = FALSE;
bal_state.balancing_threshold = BAL_THRESHOLD_MV;
bal_state.active = TRUE;
bal_balancing.enable_balancing = 1;
} else {
bal_balancing.balancing_state[i] = 0;
}
}
bal_balancing.previous_timestamp = bal_balancing.timestamp;
bal_balancing.timestamp = OS_getOSSysTick();
DB_WriteBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
return finished;
}
#else
static uint8_t BAL_Check_Imbalances(void) {
uint16_t i;
uint8_t retVal = FALSE;
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
if (bal_balancing.delta_charge[i] > 0) {
retVal = TRUE;
}
}
return retVal;
}
static void BAL_Compute_Imbalances(void) {
uint16_t i = 0;
uint16_t voltageMin = 0;
uint16_t minVoltageIndex = 0;
float SOC = 0.0;
uint32_t DOD = 0.0;
uint32_t maxDOD = 0.0;
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
DB_ReadBlock(&bal_cellvoltage, DATA_BLOCK_ID_CELLVOLTAGE);
voltageMin = bal_cellvoltage.voltage[0];
minVoltageIndex = 0;
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
if (bal_cellvoltage.voltage[i] <= voltageMin) {
voltageMin = bal_cellvoltage.voltage[i];
minVoltageIndex = i;
}
}
SOC = SOC_GetFromVoltage(((float)(bal_cellvoltage.voltage[minVoltageIndex]))/1000.0);
maxDOD = BC_CAPACITY * (uint32_t)((1.0 - SOC) * 3600.0);
bal_balancing.delta_charge[minVoltageIndex] = 0;
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
if (i != minVoltageIndex) {
if (bal_cellvoltage.voltage[i] >= voltageMin + bal_state.balancing_threshold) {
SOC = SOC_GetFromVoltage(((float)(bal_cellvoltage.voltage[i]))/1000.0);
DOD = BC_CAPACITY * (uint32_t)((1.0 - SOC) * 3600.0);
bal_balancing.delta_charge[i] = (maxDOD - DOD);
}
}
}
DB_WriteBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
}
static void BAL_Activate_Balancing_History(void) {
uint16_t i;
float cellBalancingCurrent;
uint32_t difference;
DB_ReadBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
DB_ReadBlock(&bal_cellvoltage, DATA_BLOCK_ID_CELLVOLTAGE);
for (i=0; i < BS_NR_OF_BAT_CELLS; i++) {
if (bal_state.balancing_allowed == FALSE) {
bal_balancing.balancing_state[i] = 0;
} else {
if (bal_balancing.delta_charge[i] > 0) {
bal_balancing.balancing_state[i] = 1;
cellBalancingCurrent = ((float)(bal_cellvoltage.voltage[i]))/BS_BALANCING_RESISTANCE_OHM;
difference = (BAL_STATEMACH_BALANCINGTIME_100MS/10) * (uint32_t)(cellBalancingCurrent);
bal_state.active = TRUE;
bal_balancing.enable_balancing = 1;
/* we are working with unsigned integers */
if (difference > bal_balancing.delta_charge[i]) {
bal_balancing.delta_charge[i] = 0;
} else {
bal_balancing.delta_charge[i] -= difference;
}
} else {
bal_balancing.balancing_state[i] = 0;
}
}
}
DB_WriteBlock(&bal_balancing, DATA_BLOCK_ID_BALANCING_CONTROL_VALUES);
}
#endif
/**
* @brief re-entrance check of BAL state machine trigger function
*
* This function is not re-entrant and should only be called time- or event-triggered.
* It increments the triggerentry counter from the state variable bal_state.
* It should never be called by two different processes, so if it is the case, triggerentry
* should never be higher than 0 when this function is called.
*
*
* @return retval 0 if no further instance of the function is active, 0xff else
*
*/
static uint8_t BAL_CheckReEntrance(void) {
uint8_t retval = 0;
taskENTER_CRITICAL();
if (!bal_state.triggerentry) {
bal_state.triggerentry++;
} else {
retval = 0xFF; /* multiple calls of function */
}
taskEXIT_CRITICAL();
return (retval);
}
/**
* @brief gets the current state request.
*
* This function is used in the functioning of the BAL state machine.
*
* @return retval current state request, taken from BAL_STATE_REQUEST_e
*/
static BAL_STATE_REQUEST_e BAL_GetStateRequest(void) {
BAL_STATE_REQUEST_e retval = BAL_STATE_NO_REQUEST;
taskENTER_CRITICAL();
retval = bal_state.statereq;
taskEXIT_CRITICAL();
return (retval);
}
BAL_STATEMACH_e BAL_GetState(void) {
return (bal_state.state);
}
STD_RETURN_TYPE_e BAL_GetInitializationState(void) {
return (bal_state.initFinished);
}
/**
* @brief transfers the current state request to the state machine.
*
* This function takes the current state request from bal_state and transfers it to the state machine.
* It resets the value from bal_state to BAL_STATE_NO_REQUEST
*
* @return retVal current state request, taken from BAL_STATE_REQUEST_e
*
*/
static BAL_STATE_REQUEST_e BAL_TransferStateRequest(void) {
BAL_STATE_REQUEST_e retval = BAL_STATE_NO_REQUEST;
taskENTER_CRITICAL();
retval = bal_state.statereq;
bal_state.statereq = BAL_STATE_NO_REQUEST;
taskEXIT_CRITICAL();
return (retval);
}
BAL_RETURN_TYPE_e BAL_SetStateRequest(BAL_STATE_REQUEST_e statereq) {
BAL_RETURN_TYPE_e retVal = BAL_STATE_NO_REQUEST;
taskENTER_CRITICAL();
retVal = BAL_CheckStateRequest(statereq);
if (retVal == BAL_OK) {
bal_state.statereq = statereq;
}
taskEXIT_CRITICAL();
return (retVal);
}
/**
* @brief checks the state requests that are made.
*
* This function checks the validity of the state requests.
* The resuls of the checked is returned immediately.
*
* @param statereq state request to be checked
*
* @return result of the state request that was made, taken from BAL_RETURN_TYPE_e
*/
static BAL_RETURN_TYPE_e BAL_CheckStateRequest(BAL_STATE_REQUEST_e statereq) {
if (statereq == BAL_STATE_ERROR_REQUEST) {
return BAL_OK;
}
if (statereq == BAL_STATE_GLOBAL_ENABLE_REQUEST) {
bal_state.balancing_global_allowed = 1;
return BAL_OK;
}
if (statereq == BAL_STATE_GLOBAL_DISABLE_REQUEST) {
bal_state.balancing_global_allowed = 0;
return BAL_OK;
}
if ((statereq == BAL_STATE_NOBALANCING_REQUEST) || (statereq == BAL_STATE_ALLOWBALANCING_REQUEST)) {
return BAL_OK;
}
if (bal_state.statereq == BAL_STATE_NO_REQUEST) {
/* init only allowed from the uninitialized state */
if (statereq == BAL_STATE_INIT_REQUEST) {
if (bal_state.state == BAL_STATEMACH_UNINITIALIZED) {
return BAL_OK;
} else {
return BAL_ALREADY_INITIALIZED;
}
/* request to forbid balancing */
} else {
return BAL_ILLEGAL_REQUEST;
}
} else {
return BAL_REQUEST_PENDING;
}
}
void BAL_Trigger(void) {
BAL_STATE_REQUEST_e statereq = BAL_STATE_NO_REQUEST;
uint8_t finished = FALSE;
if (bal_state.rest_timer > 0) {
bal_state.rest_timer--;
}
/* Check re-entrance of function */
if (BAL_CheckReEntrance()) {
return;
}
if (bal_state.timer) {
if (--bal_state.timer) {
bal_state.triggerentry--;
return; /* handle state machine only if timer has elapsed */
}
}
/* Check if battery is resting */
if (BS_CheckCurrent_Direction() == BS_CURRENT_NO_CURRENT) {
if (bal_state.resting == FALSE) {
bal_state.resting = TRUE;
bal_state.rest_timer = BAL_TIME_BEFORE_BALANCING_S*10;
}
} else {
bal_state.resting = FALSE;
}
switch (bal_state.state) {
/****************************UNINITIALIZED***********************************/
case BAL_STATEMACH_UNINITIALIZED:
/* waiting for Initialization Request */
statereq = BAL_TransferStateRequest();
if (statereq == BAL_STATE_INIT_REQUEST) {
BAL_SAVELASTSTATES();
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
bal_state.state = BAL_STATEMACH_INITIALIZATION;
bal_state.substate = BAL_ENTRY;
} else if (statereq == BAL_STATE_NO_REQUEST) {
/* no actual request pending */
} else {
bal_state.ErrRequestCounter++; /* illegal request pending */
}
break;
/****************************INITIALIZATION**********************************/
case BAL_STATEMACH_INITIALIZATION:
BAL_SAVELASTSTATES();
BAL_Init();
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
bal_state.state = BAL_STATEMACH_INITIALIZED;
bal_state.substate = BAL_ENTRY;
break;
/****************************INITIALIZED*************************************/
case BAL_STATEMACH_INITIALIZED:
BAL_SAVELASTSTATES();
bal_state.initFinished = E_OK;
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
break;
#if BALANCING_VOLTAGE_BASED == FALSE
/****************************CHECK_BALANCING*************************************/
case BAL_STATEMACH_CHECK_BALANCING:
BAL_SAVELASTSTATES();
if (bal_state.substate == BAL_ENTRY) {
if (bal_state.balancing_global_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.active = FALSE;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.substate = BAL_CHECK_IMBALANCES;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
} else if (bal_state.substate == BAL_CHECK_IMBALANCES) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
if (BAL_Check_Imbalances() == TRUE) {
bal_state.state = BAL_STATEMACH_BALANCE;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.substate = BAL_COMPUTE_IMBALANCES;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
} else if (bal_state.substate == BAL_COMPUTE_IMBALANCES) {
if (bal_state.rest_timer == 0) {
BAL_Compute_Imbalances();
bal_state.state = BAL_STATEMACH_BALANCE;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.substate = BAL_CHECK_IMBALANCES;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
}
break;
/****************************BALANCE*************************************/
case BAL_STATEMACH_BALANCE:
BAL_SAVELASTSTATES();
if (bal_state.substate == BAL_ENTRY) {
if (bal_state.balancing_global_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.active = FALSE;
bal_state.substate = BAL_STATEMACH_CHECK_BALANCING;
} else {
bal_state.substate = BAL_ACTIVATE_BALANCING;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
} else if (bal_state.substate == BAL_ACTIVATE_BALANCING) {
DB_ReadBlock(&bal_minmax, DATA_BLOCK_ID_MINMAX);
/* do not balance under a certain voltage level */
if (bal_minmax.voltage_min <= BAL_LOWER_VOLTAGE_LIMIT_MV ||
bal_minmax.temperature_max >= BAL_UPPER_TEMPERATURE_LIMIT_DEG ||
BAL_Check_Imbalances() == FALSE ||
bal_state.balancing_global_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
break;
} else {
BAL_Activate_Balancing_History();
bal_state.timer = BAL_STATEMACH_BALANCINGTIME_100MS;
break;
}
}
break;
#else /* voltage-based balancing */
case BAL_STATEMACH_CHECK_BALANCING:
BAL_SAVELASTSTATES();
statereq = BAL_TransferStateRequest();
if (statereq == BAL_STATE_NOBALANCING_REQUEST) {
bal_state.balancing_allowed = FALSE;
}
if (statereq == BAL_STATE_ALLOWBALANCING_REQUEST) {
bal_state.balancing_allowed = TRUE;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
if (bal_state.balancing_allowed == FALSE || bal_state.balancing_global_allowed == FALSE) {
BAL_Deactivate();
bal_state.active = FALSE;
} else {
if (bal_state.rest_timer == 0) {
bal_state.state = BAL_STATEMACH_BALANCE;
bal_state.substate = BAL_ENTRY;
}
}
break;
/****************************BALANCE*************************************/
case BAL_STATEMACH_BALANCE:
BAL_SAVELASTSTATES();
/* Check if balancing is still allowed */
statereq = BAL_TransferStateRequest();
if (statereq == BAL_STATE_NOBALANCING_REQUEST) {
bal_state.balancing_allowed = FALSE;
}
if (statereq == BAL_STATE_ALLOWBALANCING_REQUEST) {
bal_state.balancing_allowed = TRUE;
}
if (bal_state.balancing_global_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.active = FALSE;
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
}
if (bal_state.substate == BAL_ENTRY) {
if (bal_state.balancing_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.active = FALSE;
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.substate = BAL_CHECK_LOWEST_VOLTAGE;
}
bal_state.timer = BAL_STATEMACH_SHORTTIME_100MS;
break;
} else if (bal_state.substate == BAL_CHECK_LOWEST_VOLTAGE) {
DB_ReadBlock(&bal_minmax, DATA_BLOCK_ID_MINMAX);
/* stop balacing if minimum voltage is below minimum threshold or maximum cell temperature breached upper temperature limit */
if (bal_minmax.voltage_min <= BAL_LOWER_VOLTAGE_LIMIT_MV ||
bal_minmax.temperature_max >= BAL_UPPER_TEMPERATURE_LIMIT_DEG) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.substate = BAL_CHECK_CURRENT;
}
bal_state.timer = BAL_STATEMACH_BALANCINGTIME_100MS;
break;
} else if (bal_state.substate == BAL_CHECK_CURRENT) {
if (bal_state.rest_timer == 0) {
bal_state.substate = BAL_ACTIVATE_BALANCING;
} else {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
}
bal_state.timer = BAL_STATEMACH_BALANCINGTIME_100MS;
break;
} else if (bal_state.substate == BAL_ACTIVATE_BALANCING) {
if (bal_state.balancing_allowed == FALSE) {
if (bal_state.active == TRUE) {
BAL_Deactivate();
}
bal_state.active = FALSE;
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
} else {
finished = BAL_Activate_Balancing_Voltage();
if (finished == TRUE) {
bal_state.balancing_threshold = BAL_THRESHOLD_MV + BAL_HYSTERESIS_MV;
bal_state.state = BAL_STATEMACH_CHECK_BALANCING;
bal_state.substate = BAL_ENTRY;
} else {
bal_state.state = BAL_STATEMACH_BALANCE;
bal_state.substate = BAL_ENTRY;
}
}
bal_state.timer = BAL_STATEMACH_BALANCINGTIME_100MS;
break;
}
break;
#endif /* endif balancing type */
default:
break;
} /* end switch (bal_state.state) */
bal_state.triggerentry--;
}
bal.h¶
/**
*
* @copyright © 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file bal.h
* @author foxBMS Team
* @date 26.02.2016 (date of creation)
* @ingroup DRIVERS
* @prefix BAL
*
* @brief Header for the driver for balancing
*
*/
#ifndef BAL_H_
#define BAL_H_
/*================== Includes =============================================*/
#include "bal_cfg.h"
/*================== Macros and Definitions ===============================*/
/*================== Constant and Variable Definitions ====================*/
/*================== Function Prototypes ==================================*/
/*================== Function Implementations =============================*/
/*================== Constant and Variable Definitions ====================*/
/**
* States of the BAL state machine
*/
typedef enum {
/* Init-Sequence */
BAL_STATEMACH_UNINITIALIZED = 0, /*!< */
BAL_STATEMACH_INITIALIZATION = 1, /*!< */
BAL_STATEMACH_INITIALIZED = 2, /*!< */
BAL_STATEMACH_CHECK_BALANCING = 3, /*!< */
BAL_STATEMACH_BALANCE = 4, /*!< */
BAL_STATEMACH_NOBALANCING = 5, /*!< */
BAL_STATEMACH_ALLOWBALANCING = 6, /*!< */
BAL_STATEMACH_GLOBALDISABLE = 7, /*!< */
BAL_STATEMACH_GLOBALENABLE = 8, /*!< */
BAL_STATEMACH_UNDEFINED = 20, /*!< undefined state */
BAL_STATEMACH_RESERVED1 = 0x80, /*!< reserved state */
BAL_STATEMACH_ERROR = 0xF0, /*!< Error-State: */
} BAL_STATEMACH_e;
/**
* Substates of the BAL state machine
*/
typedef enum {
BAL_ENTRY = 0, /*!< Substate entry state */
BAL_CHECK_IMBALANCES = 1, /*!< Check if balancing has been initialized */
BAL_COMPUTE_IMBALANCES = 2, /*!< Compute imbalances */
BAL_ACTIVATE_BALANCING = 3, /*!< Activated balancing resistors */
BAL_CHECK_LOWEST_VOLTAGE = 4, /*!< Check if lowest voltage is still above limit */
BAL_CHECK_CURRENT = 5, /*!< Check if current is still under limit */
} BAL_STATEMACH_SUB_e;
/**
* State requests for the BAL statemachine
*/
typedef enum {
BAL_STATE_INIT_REQUEST = BAL_STATEMACH_INITIALIZATION, /*!< */
BAL_STATE_ERROR_REQUEST = BAL_STATEMACH_ERROR, /*!< */
BAL_STATE_NOBALANCING_REQUEST = BAL_STATEMACH_NOBALANCING, /*!< */
BAL_STATE_ALLOWBALANCING_REQUEST = BAL_STATEMACH_ALLOWBALANCING, /*!< */
BAL_STATE_GLOBAL_DISABLE_REQUEST = BAL_STATEMACH_GLOBALDISABLE, /*!< */
BAL_STATE_GLOBAL_ENABLE_REQUEST = BAL_STATEMACH_GLOBALENABLE, /*!< */
BAL_STATE_NO_REQUEST = BAL_STATEMACH_RESERVED1, /*!< */
} BAL_STATE_REQUEST_e;
/**
* Possible return values when state requests are made to the BAL statemachine
*/
typedef enum {
BAL_OK = 0, /*!< BAL --> ok */
BAL_BUSY_OK = 1, /*!< BAL busy */
BAL_REQUEST_PENDING = 2, /*!< requested to be executed */
BAL_ILLEGAL_REQUEST = 3, /*!< Request can not be executed */
BAL_INIT_ERROR = 7, /*!< Error state: Source: Initialization */
BAL_OK_FROM_ERROR = 8, /*!< Return from error --> ok */
BAL_ERROR = 20, /*!< General error state */
BAL_ALREADY_INITIALIZED = 30, /*!< Initialization of BAL already finished */
BAL_ILLEGAL_TASK_TYPE = 99, /*!< Illegal */
} BAL_RETURN_TYPE_e;
/**
* This structure contains all the variables relevant for the BAL state machine.
* The user can get the current state of the BAL state machine with this variable
*/
typedef struct {
uint16_t timer; /*!< time in ms before the state machine processes the next state, e.g. in counts of 1ms */
BAL_STATE_REQUEST_e statereq; /*!< current state request made to the state machine */
BAL_STATEMACH_e state; /*!< state of Driver State Machine */
BAL_STATEMACH_SUB_e substate; /*!< current substate of the state machine */
BAL_STATEMACH_e laststate; /*!< previous state of the state machine */
uint8_t lastsubstate; /*!< previous substate of the state machine */
uint8_t triggerentry; /*!< counter for re-entrance protection (function running flag) */
uint32_t ErrRequestCounter; /*!< counts the number of illegal requests to the BAL state machine */
STD_RETURN_TYPE_e initFinished; /*!< E_OK if statemachine initialized, otherwise E_NOT_OK */
uint8_t active; /*!< indicate if balancing active or not */
uint8_t resting; /*!< indicate if current flowing through battery or not */
uint32_t rest_timer; /*!< counter since last timestamp with no current flowing */
uint32_t balancing_threshold; /*!< effective balancing threshold */
uint8_t balancing_allowed; /*!< flag to disable balancing */
uint8_t balancing_global_allowed; /*!< flag to globally disable balancing */
} BAL_STATE_s;
/*================== Function Prototypes ==================================*/
/**
* @brief sets the current state request of the state variable bal_state.
*
* This function is used to make a state request to the state machine,e.g, start voltage measurement,
* read result of voltage measurement, re-initialization
* It calls BAL_CheckStateRequest() to check if the request is valid.
* The state request is rejected if is not valid.
* The result of the check is returned immediately, so that the requester can act in case
* it made a non-valid state request.
*
* @param statereq state request to set
*
* @return retVal current state request, taken from BAL_STATE_REQUEST_e
*/
extern BAL_RETURN_TYPE_e BAL_SetStateRequest(BAL_STATE_REQUEST_e statereq);
/**
* @brief gets the current state.
*
* This function is used in the functioning of the BAL state machine.
*
* @return current state, taken from BAL_STATEMACH_e
*/
extern BAL_STATEMACH_e BAL_GetState(void);
/**
* @brief gets the initialization state.
*
* This function is used for getting the balancing initialization state
*
* @return E_OK if initialized, otherwise E_NOT_OK
*/
extern STD_RETURN_TYPE_e BAL_GetInitializationState(void);
/**
* @brief trigger function for the BAL driver state machine.
*
* This function contains the sequence of events in the BAL state machine.
* It must be called time-triggered, every 1ms.
*/
extern void BAL_Trigger(void);
#endif /* BAL_H_ */
bal_cfg.c¶
/**
*
* @copyright © 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file bal_cfg.c
* @author foxBMS Team
* @date 26.02.2016 (date of creation)
* @ingroup DRIVERS_CONF
* @prefix BAL
*
* @brief Configuration for the driver for balancing.
*
*/
/*================== Includes =============================================*/
#include "bal_cfg.h"
/*================== Macros and Definitions ===============================*/
/*================== Constant and Variable Definitions ====================*/
/*================== Function Prototypes ==================================*/
/*================== Function Implementations =============================*/
bal_cfg.h¶
/**
*
* @copyright © 2010 - 2019, Fraunhofer-Gesellschaft zur Foerderung der
* angewandten Forschung e.V. All rights reserved.
*
* BSD 3-Clause License
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* We kindly request you to use one or more of the following phrases to refer
* to foxBMS in your hardware, software, documentation or advertising
* materials:
*
* ″This product uses parts of foxBMS®″
*
* ″This product includes parts of foxBMS®″
*
* ″This product is derived from foxBMS®″
*
*/
/**
* @file bal_cfg.h
* @author foxBMS Team
* @date 26.02.2016 (date of creation)
* @ingroup DRIVERS_CONF
* @prefix BAL
*
* @brief Header for the configuration for the driver for balancing
*
*/
#ifndef BAL_CFG_H_
#define BAL_CFG_H_
/*================== Includes =============================================*/
#include "general.h"
/*================== Macros and Definitions ===============================*/
/**
* BAL statemachine short time definition in 100*ms
*/
#define BAL_STATEMACH_SHORTTIME_100MS 1
/**
* BAL statemachine long time definition in 100*ms
*/
#define BAL_STATEMACH_LONGTIME_100MS 50
/**
* BAL statemachine balancing time in 100*ms
*/
#define BAL_STATEMACH_BALANCINGTIME_100MS 10
/**
* BAL time to wait in seconds before balancing once no current flowing
*/
#define BAL_TIME_BEFORE_BALANCING_S 600
/**
* BAL voltage threshold for balancing in mV
*/
#define BAL_THRESHOLD_MV 200
/**
* BAL hysteresis for voltage threshold when balancing was finished in mV
*/
#define BAL_HYSTERESIS_MV 200
/**
* BAL lower voltage limit in MV
*/
#define BAL_LOWER_VOLTAGE_LIMIT_MV 2000
/**
* BAL upper temperature limit in Celsius
*/
#define BAL_UPPER_TEMPERATURE_LIMIT_DEG 70
/**
* If set to FALSE, SOC-history based balancing is used.
* An open-circuit-voltage/SOC look-up table is needed.
* If set to TRUE, voltage-based balancing is used.
*
*/
#define BALANCING_VOLTAGE_BASED TRUE
/*================== Constant and Variable Definitions ====================*/
/*================== Function Prototypes ==================================*/
/*================== Function Implementations =============================*/
#endif /* BAL_CFG_H_ */