Files
LFP_48V_mBMS_FW/APP_R3323/App/Source/afe_comm.c

1049 lines
30 KiB
C

/**
******************************************************************************
* @file afe_comm.c
* @author AMG Energy Solution Team
* @version V1.0.0
* @date 21-Jul-2025
* @brief This file provides all the headers of afe communication functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2025 AMG</center></h2>
******************************************************************************
*/
/** @addtogroup mBMS3
* @{
*/
/* Includes ------------------------------------------------------------------*/
#include <includes.h>
#include "afe_comm.h"
#include "spi.h"
#include "ADBMS181x.h"
#include "ADBMS1818.h"
#include "usart.h"
#include "asutil.h"
#include "malloc.h"
#include "delay.h"
#include "device_param.h"
#include "brtc.h"
#include "console.h"
#include "io.h"
/* Private typedef -----------------------------------------------------------*/
typedef struct
{
uint16_t cvolt[DEVICE_MAX_CELL];
} TPackBuf, *PPackBuf;
/* Private define ------------------------------------------------------------*/
#define ENABLED 1
#define DISABLED 0
#define DATALOG_ENABLED 1
#define DATALOG_DISABLED 0
#define BATT_TASK_TIME 30 // 30ms TASK
#define DEFAULT_HOST_BALANCING_VOLTAGE 3000
/**********************************************************
Setup Variables
The following variables can be modified to
configure the software.
***********************************************************/
const uint8_t TOTAL_IC = 1;//!<number of ICs in the daisy chain
/*************************************************************************
ADC Command Configurations. See LTC681x.h for options
**************************************************************************/
const uint8_t ADC_OPT = ADC_OPT_DISABLED; //!< ADC Mode option bit
const uint8_t ADC_CONVERSION_MODE = MD_7KHZ_3KHZ; //!< ADC Mode
const uint8_t ADC_DCP = DCP_ENABLED; //!< Discharge Permitted
const uint8_t CELL_CH_TO_CONVERT = CELL_CH_ALL; //!< Channel Selection for ADC conversion
const uint8_t AUX_CH_TO_CONVERT = AUX_CH_ALL; //!< Channel Selection for ADC conversion
const uint8_t STAT_CH_TO_CONVERT = STAT_CH_ALL; //!< Channel Selection for ADC conversion
const uint8_t NO_OF_REG = 0; //REG_ALL; //!< Register Selection
const uint16_t MEASUREMENT_LOOP_TIME = 500; //!< Loop Time in milliseconds(ms)
//Under Voltage and Over Voltage Thresholds
const uint16_t OV_THRESHOLD = 41000; //!< Over voltage threshold ADC Code. LSB = 0.0001 ---(4.1V)
const uint16_t UV_THRESHOLD = 20000; //!< Under voltage threshold ADC Code. LSB = 0.0001 ---(3V)
//Loop Measurement Setup. These Variables are ENABLED or DISABLED. Remember ALL CAPS
const uint8_t WRITE_CONFIG = DISABLED; //!< Loop Measurement Setup
const uint8_t READ_CONFIG = DISABLED; //!< Loop Measurement Setup
const uint8_t MEASURE_CELL = ENABLED; //!< Loop Measurement Setup
const uint8_t MEASURE_AUX = ENABLED; //!< Loop Measurement Setup
const uint8_t MEASURE_STAT = DISABLED; //!< Loop Measurement Setup
const uint8_t PRINT_PEC = DISABLED; //!< Loop Measurement Setup
/************************************
END SETUP
*************************************/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/*******************************************************
Global Battery Variables received from 681x commands
These variables store the results from the LTC6813
register reads and the array lengths must be based
on the number of ICs on the stack
******************************************************/
cell_asic bms_ic[TOTAL_IC]; //!< Global Battery Variable
/*************************************************************************
Set configuration register. Refer to the data sheet
**************************************************************************/
bool REFON = true; //!< Reference Powered Up Bit
bool ADCOPT = false; //!< ADC Mode option bit
bool gpioBitsA[5] = { 0, 0, 0, 0, 0 };
bool gpioBitsB[4] = { 0, 0, 0, 0 };
//uint8_t gpioBits_a = 0x1F; //!< GPIO Pin Control // Gpio 1,2,3,4,5
//uint8_t gpioBits_b = 0x0F; //!< GPIO Pin Control // Gpio 6,7,8,9
uint16_t UV = UV_THRESHOLD; //!< Under voltage Comparison Voltage
uint16_t OV = OV_THRESHOLD; //!< Over voltage Comparison Voltage
bool dccBitsA[12] = { 0, };
bool dccBitsB[7] = { 0, };
//uint16_t dccBits_a = 0; // 12bits !< Discharge cell switch //Dcc 1,2,3,4,5,6,7,8,9,10,11,12
//uint16_t dccBits_b = 0; // 7bits !< Discharge cell switch //Dcc 13,14,15,16,17,18, GPIO9
bool dctoBits[4] = { 0, 0, 0, 0 };
//uint8_t dctoBits = 1; // 4bits !< Discharge time value //Dcto 0,1,2,3 // Programed for 0.5 min
/*Ensure that Dcto bits are set according to the required discharge time. Refer to the data sheet */
bool FDRF = false; //!< Force Digital Redundancy Failure Bit
bool DTMEN = true; //!< Enable Discharge Timer Monitor
bool psBits[2]= {false,false}; //!< Digital Redundancy Path Selection//ps-0,1
#define PACK_BUF_MAX 20
uint16_t PackBufCh = 0;
TPackBuf PackBuf[PACK_BUF_MAX];
uint8_t PackBuffFlag = false;
uint32_t OneBuffTime = 0;
uint32_t AllBuffTime = 0;
uint32_t bakOneBuffTime = 0;
uint32_t bakAllBuffTime = 0;
uint32_t Balance_Avg, disBalance_Avg;
uint8_t CellBalancingFlag = false, disCellBalancingFlag;
uint8_t CellBalancingOff = false;
uint16_t HostBalancingVoltage = 0;
uint16_t HostBalancingVoltageDiff = 0;
uint8_t CB_Rest = 1;
uint32_t CB_Tick = 0;
uint32_t disCB_Tick = 0;
uint32_t CbRestAlarmTick = 0;
uint32_t ManualBalValue = 0;
uint8_t ManualBalFlag = 0;
uint32_t bakManualBalValue = 0;
uint32_t cBal = 0;
/* Private function prototypes -----------------------------------------------*/
void setup(void);
void cell_balancing_init(void);
void ReadCellVoltage(uint8_t cNo, cell_asic *ic);
void CellVoltagePutBuf(uint8_t cNo, cell_asic *ic);
void MakeCellAvgData(void);
void TempVoltagePutBuf(uint8_t cNo, cell_asic *ic);
void WriteBalData(uint32_t wBal);
void AutoCellBalancing(uint32_t rBal);
void ManualCellBalancing(uint32_t rBal);
/* Private functions ---------------------------------------------------------*/
/*!**********************************************************************
\brief Initializes Port
@return void
***********************************************************************/
void init_battery_interface(void)
{
stc_port_init_t stcPortInit;
/* configure structure initialization */
MEM_ZERO_STRUCT(stcPortInit);
stcPortInit.enPinMode = Pin_Mode_Out;
PORT_Init(SPI1_NSS_PORT, SPI1_NSS_PIN, &stcPortInit);
CS_PIN_HIGH();
Spi1_Config();
wakeup_sleep(1);
setup();
cell_balancing_init();
device_status.battery_status.bit.ACB = true;
}
/*!**********************************************************************
\brief Initializes hardware and variables
@return void
***********************************************************************/
void setup(void)
{
ADBMS1818_init_cfg(TOTAL_IC, bms_ic);
ADBMS1818_init_cfgb(TOTAL_IC, bms_ic);
for (uint8_t current_ic = 0; current_ic < TOTAL_IC; current_ic++) {
ADBMS1818_set_cfgr (current_ic, bms_ic, REFON, ADCOPT, gpioBitsA, dccBitsA , dctoBits, UV, OV);
ADBMS1818_set_cfgrb(current_ic, bms_ic, FDRF , DTMEN , psBits , gpioBitsB, dccBitsB);
}
ADBMS1818_reset_crc_count(TOTAL_IC, bms_ic);
ADBMS1818_init_reg_limits(TOTAL_IC, bms_ic);
}
/**
* @brief Application Task for AFE (Analog Front End) Communication
* @param None
* @retval None
*/
void App_TaskAfeComm(void)
{
init_battery_interface();
while (DEF_TRUE) {
ReadCellVoltage(0, bms_ic);
delay_os_ms(BATT_TASK_TIME);
}
}
/*!**********************************************************************
\brief Initialize cell balancing
@return void
***********************************************************************/
void reset_dccbitA(void)
{
for (int i = 0; i < 12; i++) { dccBitsA[i] = 0; }
}
void reset_dccbitB(void)
{
for (int i = 0; i < 7; i++) { dccBitsB[i] = 0; }
}
void cell_balancing_init(void)
{
for (int i = 0; i < 18; i++)
{
wakeup_sleep(TOTAL_IC);
wakeup_idle(TOTAL_IC);
WriteBalData((uint32_t)(1 << i));
delay_os_ms(200);
}
wakeup_sleep(TOTAL_IC);
wakeup_idle(TOTAL_IC);
WriteBalData((uint32_t)(0xFFFFFFFF));
delay_os_ms(1000);
reset_dccbitA();
reset_dccbitB();
ADBMS1818_set_cfgr (0, bms_ic, REFON, ADCOPT, gpioBitsA, dccBitsA , dctoBits, UV, OV);
ADBMS1818_set_cfgrb(0, bms_ic, FDRF , DTMEN , psBits , gpioBitsB, dccBitsB);
wakeup_sleep(TOTAL_IC);
wakeup_idle(TOTAL_IC);
ADBMS1818_wrcfg (TOTAL_IC, bms_ic);
ADBMS1818_wrcfgb(TOTAL_IC, bms_ic);
ADBMS1818_adcv(ADC_CONVERSION_MODE, ADC_DCP, CELL_CH_TO_CONVERT);
}
/*!*********************************************************************
\brief Cell Voltage Read
@return void
***********************************************************************/
void ReadCellVoltage(uint8_t cNo, cell_asic *ic)
{
int8_t error;
int8_t errorA, errorB;
wakeup_sleep(TOTAL_IC);
wakeup_idle(TOTAL_IC);
errorA = ADBMS1818_rdcfg (TOTAL_IC, ic);
errorB = ADBMS1818_rdcfgb(TOTAL_IC, ic);
if ((errorA != -1) && (errorB != -1)) {
// Process cell balancing
uint32_t bal = 0;
bal = (((ic[0].config.rx_data[4] << 0) & 0x000000FF)
|((ic[0].config.rx_data[5] << 8) & 0x00000F00)
|((ic[0].configb.rx_data[0] << 8) & 0x0000F000)
|((ic[0].configb.rx_data[1] << 16) & 0x00030000)
);
device_status.cellbalance.value = bal;
if (ManualBalFlag == true) {
ManualCellBalancing(bal);
} else {
AutoCellBalancing(bal);
}
}
/* Always attempt a fresh measurement; check the read result before using it. */
wakeup_sleep(TOTAL_IC);
wakeup_idle(TOTAL_IC);
ADBMS1818_adcv(ADC_CONVERSION_MODE, ADC_DCP, CELL_CH_TO_CONVERT);
uint16_t conv_time = ADBMS1818_pollAdc();
wakeup_idle(TOTAL_IC);
error = ADBMS1818_rdcv(NO_OF_REG, TOTAL_IC, ic); // Set to read back all cell voltage registers
if (error != -1) {
CellVoltagePutBuf(0, ic);
MakeCellAvgData();
}
}
void inc_afe_bufftime(uint32_t tick)
{
OneBuffTime += tick;
AllBuffTime += tick;
}
void SaveOneBuffTime(void)
{
bakOneBuffTime = OneBuffTime;
OneBuffTime = 0;
}
void SaveAllBuffTime(void)
{
bakAllBuffTime = AllBuffTime;
AllBuffTime = 0;
}
uint32_t GetOneBuffTime(void)
{
return bakOneBuffTime;
}
uint32_t GetAllBuffTime(void)
{
return bakAllBuffTime;
}
// Data Buffering
void CellVoltagePutBuf(uint8_t cNo, cell_asic *ic)
{
int32_t ch, tmp;
ch = PackBufCh;
// data buffering
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
if (ic[cNo].cells.c_codes[i] > 50000) {
return;
}
if (i == 0) { ic[cNo].cells.c_codes[i] += 0; }
if (i == (DEVICE_MAX_CELL - 1)) { ic[cNo].cells.c_codes[i] += 0; }
}
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
PackBuf[ch].cvolt[i] = ic[cNo].cells.c_codes[i] / 10; // Cell n
}
if (PackBuffFlag == false) {
PackBuffFlag = true;
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
for (int j = 0; j < PACK_BUF_MAX; j++) {
PackBuf[j].cvolt[i] = ic[cNo].cells.c_codes[i] / 10; // Cell n
}
}
}
uint32_t max, min;
// Volt Avg
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
tmp = 0;
for (int j = 0; j < PACK_BUF_MAX; j++) {
if (j == 0) {
max = min = PackBuf[j].cvolt[i];
} else {
if (max < PackBuf[j].cvolt[i]) { max = PackBuf[j].cvolt[i];}
if (min > PackBuf[j].cvolt[i]) { min = PackBuf[j].cvolt[i];}
}
tmp += PackBuf[j].cvolt[i];
}
if ((GetCB_Rest() == true) || (device_status.battery_status.bit.DCP == true)) {
device_value.Cell.voltage[i] = (uint16_t)((tmp - max - min) / (PACK_BUF_MAX - 2));
}
}
SaveOneBuffTime();
if (PackBufCh == 0) { SaveAllBuffTime(); }
PackBufCh++;
PackBufCh %= PACK_BUF_MAX;
}
void MakeCellAvgData(void)
{
uint32_t sum;
TMinMax min, max;
sum = 0;
memset(&min, 0x00, sizeof(TMinMax));
memset(&max, 0x00, sizeof(TMinMax));
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
if (i == 0) {
max.value = device_value.Cell.voltage[i];
max.num = i;
min.value = device_value.Cell.voltage[i];
min.num = i;
}
if (max.value < device_value.Cell.voltage[i]) {
max.value = device_value.Cell.voltage[i];
max.num = i;
}
if (min.value > device_value.Cell.voltage[i]) {
min.value = device_value.Cell.voltage[i];
min.num = i;
}
sum += device_value.Cell.voltage[i];
}
device_value.BatVoltage = sum / 10;
device_value.Cell.avg.Max.value = max.value;
device_value.Cell.avg.Max.num = max.num;
device_value.Cell.avg.Min.value = min.value;
device_value.Cell.avg.Min.num = min.num;
device_value.Cell.avg.diff = max.value - min.value;
device_value.Cell.avg.avg = (uint16_t)(sum / DEVICE_MAX_CELL);
}
// Cell Balancing Flag
void clear_cb_value(void)
{
CB_Tick = 0;
CB_Rest = 1;
CbRestAlarmTick = (1 * 1000 / 5);
}
void dec_cb_tick(uint16_t tick)
{
if (CB_Tick > tick) {
CB_Tick -= tick;
} else {
CB_Tick = 0;
}
if (CbRestAlarmTick > tick) {
CbRestAlarmTick -= tick;
} else {
CbRestAlarmTick = 0;
}
}
uint8_t GetCB_Rest(void)
{
if (((CB_Rest == 1) || (CB_Rest == 3)) && (CbRestAlarmTick == 0)) {
return 1;
} else {
return 0;
}
}
void CheckAutoBalancingEnable(void)
{
PDEVICE_PARAM param = &device_param;
// Check Cell balanicng Mode (Balancing active or not)
if (CellBalancingFlag == true) {
// Before cell balancing status is ON
if (device_value.Cell.avg.Max.value < param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold) {
CellBalancingFlag = false;
} else if (device_value.Cell.avg.diff < (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min - 5)) {
if (device_status.warning.bit.cell_over_voltage == 0) {
CellBalancingFlag = false;
}
}
} else {
// Before cell balancing status is OFF
if (device_value.Cell.avg.Max.value > (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold + param->chg_ctrl.cell_bal_cfg.Cell_Balance_Window)) {
if (device_value.Cell.avg.diff > param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min) {
CellBalancingFlag = true;
} else if (device_status.warning.bit.cell_over_voltage) {
CellBalancingFlag = true;
} else {
// Host balancing control prio
if (HostBalancingVoltage > DEFAULT_HOST_BALANCING_VOLTAGE) {
CellBalancingFlag = true;
}
}
}
}
if (CellBalancingFlag == false) {
if ((HostBalancingVoltage > DEFAULT_HOST_BALANCING_VOLTAGE) && (HostBalancingVoltageDiff > 0)) {
CellBalancingFlag = true;
}
}
}
uint32_t CalcBalancingVolt(void)
{
uint32_t balancing_avg = 0;
if (device_value.Cell.avg.diff > 100) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 20;
} else {
balancing_avg = device_value.Cell.avg.avg - 20;
}
} else if (device_value.Cell.avg.diff > 80) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 15;
} else {
balancing_avg = device_value.Cell.avg.avg - 15;
}
} else if (device_value.Cell.avg.diff > 60) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 10;
} else {
balancing_avg = device_value.Cell.avg.avg - 10;
}
} else if (device_value.Cell.avg.diff > 40) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 5;
} else {
balancing_avg = device_value.Cell.avg.avg - 5;
}
} else if (device_value.Cell.avg.diff > 30) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 2;
} else {
balancing_avg = device_value.Cell.avg.avg - 2;
}
} else if (device_value.Cell.avg.diff > 20) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 2;
} else {
balancing_avg = device_value.Cell.avg.avg - 2;
}
} else if (device_value.Cell.avg.diff > 10) {
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) {
balancing_avg = device_value.Cell.avg.avg + 1;
} else {
balancing_avg = device_value.Cell.avg.avg - 1;
}
} else {
balancing_avg = device_value.Cell.avg.avg;
}
if ((HostBalancingVoltage > DEFAULT_HOST_BALANCING_VOLTAGE) && (device_value.Cell.avg.diff < HostBalancingVoltageDiff)) {
balancing_avg = HostBalancingVoltage;
}
return balancing_avg;
}
#define REST_TIME_ADD 2000
uint8_t CheckCbRest(void)
{
uint8_t setBal = false;
if (CellBalancingFlag == true) {
if (CB_Tick == 0) {
switch (CB_Rest) {
case 0: // Work to Rest
CB_Rest = 1;
setBal = true;
CbRestAlarmTick = (1 * 1000 / 2);
CB_Tick = 1 * 1000 + REST_TIME_ADD;
break;
case 1: // Rest to Work
CB_Rest = 2;
setBal = true;
if ((device_value.Cell.avg.diff < 10) && (device_value.Cell.avg.Min.value > 3400)) {
CB_Tick = 1 * 1000 / 5;
} else {
CB_Tick = 1 * 1000 / 2;
}
break;
case 2: // Work to Rest
CB_Rest = 3;
setBal = true;
CbRestAlarmTick = (1 * 1000 / 2);
CB_Tick = 1 * 1000 + REST_TIME_ADD;
break;
case 3: // Rest to Work
CB_Rest = 0;
setBal = true;
if ((device_value.Cell.avg.diff < 10) && (device_value.Cell.avg.Min.value > 3400)) {
CB_Tick = 1 * 1000 / 5;
} else {
CB_Tick = 1 * 1000 / 2;
}
break;
default: // Rest to Work
CB_Rest = 0;
setBal = true;
CbRestAlarmTick = (1 * 1000 / 2);
CB_Tick = 1 * 1000 + REST_TIME_ADD;
break;
}
}
} else {
if ((CB_Rest == 0) || (CB_Rest == 2)) {
CB_Rest = 1;
CbRestAlarmTick = (1 * 1000 / 2);
CB_Tick = 1 * 1000 + REST_TIME_ADD;
setBal = true;
}
}
return setBal;
}
uint8_t CheckCbRest1(void)
{
uint8_t setBal = false;
PDEVICE_PARAM param = &device_param;
if (CellBalancingFlag == true) {
if (CB_Tick == 0) {
switch (CB_Rest) {
case 0: // Work to Rest
CB_Rest = 1;
setBal = true;
CbRestAlarmTick = (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5);
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 + REST_TIME_ADD;
break;
case 1: // Rest to Work
CB_Rest = 2;
setBal = true;
if ((device_value.Cell.avg.diff < 10) && (device_value.Cell.avg.Min.value > 3400)) {
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5;
} else {
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 2;
}
break;
case 2: // Work to Rest
CB_Rest = 3;
setBal = true;
CbRestAlarmTick = (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5);
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 + REST_TIME_ADD;
break;
case 3: // Rest to Work
CB_Rest = 0;
setBal = true;
if ((device_value.Cell.avg.diff < 10) && (device_value.Cell.avg.Min.value > 3400)) {
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5;
} else {
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 2;
}
break;
default: // Rest to Work
CB_Rest = 0;
setBal = true;
CbRestAlarmTick = (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5);
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 + REST_TIME_ADD;
break;
}
}
} else {
if ((CB_Rest == 0) || (CB_Rest == 2)) {
CB_Rest = 1;
CbRestAlarmTick = (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 / 5);
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
setBal = true;
}
}
return setBal;
}
void AutoCellBalancing(uint32_t rBal)
{
uint32_t bal = rBal;
uint8_t setBal = false;
setBal = CheckCbRest();
// Check Cell balanicng Mode (Balancing active or not)
CheckAutoBalancingEnable();
device_status.battery_status.bit.CB = CellBalancingFlag;
if (CellBalancingFlag == true) {
if (setBal == true) {
setBal = false;
if ((CB_Rest == 0) || (CB_Rest == 2)) {
Balance_Avg = CalcBalancingVolt();
bal = 0;
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
if ((device_value.Cell.voltage[i] > Balance_Avg) || ((device_status.cov_warning_cell.uValue >> i) == 1)) {
bal = bal | (1 << i);
}
}
// Write Balancing
cBal = bal;
WriteBalData(cBal);
} else {
// CB Rest time
bal = 0;
cBal = bal;
WriteBalData(cBal);
}
}
} else {
if (setBal) {
WriteBalData(0);
setBal = false;
}
}
}
void WriteBalData(uint32_t wBal)
{
// dccBits_a = (wBal >> 0) & 0x0FFF; // Cell #1 - #12
// dccBits_b = (wBal >> 12) & 0x0007; // Cell #13 - #15
for (int i = 0; i < 12; i++) { if ((wBal >> (i + 0)) & 0x0001) dccBitsA[i] = 1; else dccBitsA[i] = 0; }
for (int i = 0; i < 3; i++) { if ((wBal >> (i + 12)) & 0x0001) dccBitsB[i + 1] = 1; else dccBitsB[i + 1] = 0; }
ADBMS1818_set_cfgr (0, bms_ic, REFON, ADCOPT, gpioBitsA, dccBitsA , dctoBits, UV, OV);
ADBMS1818_set_cfgrb(0, bms_ic, FDRF , DTMEN , psBits , gpioBitsB, dccBitsB);
ADBMS1818_wrcfg (TOTAL_IC, bms_ic);
ADBMS1818_wrcfgb(TOTAL_IC, bms_ic);
}
void SetManualBalancing(uint8_t mode, uint8_t flag, uint32_t cNo)
{
ManualBalFlag = mode;
if (ManualBalFlag == true) {
if (cNo == 0) {
ManualBalValue = 0;
} else {
if (flag) {
ManualBalValue |= (1 << (cNo - 1));
} else {
ManualBalValue &= ~(1 << (cNo - 1));
}
}
} else {
ManualBalValue = 0;
}
}
void ManualCellBalancing(uint32_t rBal)
{
uint32_t bal = 0;
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
if ((rBal >> i) & 0x00000001) {
bal |= (uint32_t)(1 << i);
}
}
if (ManualBalFlag == true) {
if (bakManualBalValue != ManualBalValue) {
WriteBalData(ManualBalValue);
bakManualBalValue = ManualBalValue;
}
} else {
if (bal != 0) {
WriteBalData(0);
}
}
}
/* Public Status Function ************************************************************/
uint16_t GetBalanceAvg(void)
{
return Balance_Avg;
}
uint16_t GetBalanceFlag(void)
{
return device_status.battery_status.bit.CB;
}
/* Display Function ******************************************************************/
#ifdef CONSOLE_DEBUG
void AfeDisplayStatus(uint8_t p);
void ODisplayBalancingValue(uint8_t p)
{
float aParam;
if (p || (disBalance_Avg != Balance_Avg))
{
aParam = (float)Balance_Avg / 1000;
FloatNormalOutIntXY(71, 10 , aParam, 5, 3);
disBalance_Avg = Balance_Avg;
}
if (p || (disCellBalancingFlag != GetBalanceFlag()))
{
if (GetBalanceFlag() == true)
YellowOutXY(68, 11, (uint8_t *)"O");
else
GreenOutXY(68, 11, (uint8_t *)"X");
disCellBalancingFlag = GetBalanceFlag();
}
if (p || ((disCB_Tick / 1000) != (CB_Tick / 1000)))
{
aParam = (float)(disCB_Tick / 1000);
FloatNormalOutIntXY(70, 11,aParam, 6, 0);
disCB_Tick = CB_Tick;
}
//
// AfeDisplayStatus(p);
}
const char AfeMODE_STR[][84] =
{
// 1 2 3 4 5 6 7 8
// 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
"\r\n+--[Battery : ]---+---+---+---+---+---+---+---+---+---+--------------------+", // 2
"\r\n| | B |OCA|TCA|TDA|AFE|RSV|ZVC|F-C|F-D| Warning ( )HEX|", // 3
"\r\n| HeartB ( ) | S |INI|MD |FC |FD |RXM|ZVC|F-C|F-D| Protection( )HEX|", // 4
"\r\n+---------------------+---+---+---+---+---+---+---+---+---+-[CELL AVG ]--------+", // 5
"\r\n| B-Volt ( . )V | W |RSV|RSV|RSV|L-C|LTD|LTC|HTD|HTC| C-MAX ( . )V |", // 6
"\r\n| Current ( . )A | N |RSV|RSV|OCD|OCC|CUV|SUV|COV|SOV| C-AVG ( . )V |", // 7
"\r\n| SOC ( . )% +---+---+---+---+---+---+---+---+---+ C-MIN ( . )V |", // 8
"\r\n| | P |AFE|RSV|SC |RSV|LTD|LTC|HTD|HTC| C-DIFF ( . )V |", // 9
"\r\n+---------------------+ T |RSV|RSV|OCD|OCC|CUV|SUV|COV|SOV| CB AVG ( . )V |", // 0
"\r\n| F-Capa ( . )AH +---+---+---+---+---+---+---+---+---+ [ ] |", // 1
"\r\n+---------------------+ AFE STATUS ( ) UV TRIP ( ) +-[TEMP AVG ]--------+", // 2
"\r\n| Operate( )| CTRL1 ( ) OV TRIP ( ) | T-MAX ( . )C |", // 3
"\r\n| Status ( )| CTRL2 ( ) | T-AVG ( . )C |", // 4
"\r\n| | PROTECT( - - ) | T-MIN ( . )C |", // 5
"\r\n+--[Cell Volt]--------+ M( )| T-DIFF ( . )C |", // 6
"\r\n|( . )( . )( . )+---------+---------+---------+-----+---+----------------+", // 7
"\r\n|( . )( . )( . )|T1( . )|T3( . )|F1( . )| +-<INFORMATION>--+", // 8
"\r\n|( . )( . )( . )| | | | |DATE: / / |", // 9
"\r\n|( . )( . )( . )|T2( . )|T4( . )|F2( . )| |TIME: : : |", // 0
"\r\n|( . )( . )( . )| | | | |L-REBOOT ( )|", // 1
"\r\n+---------------------+---------+---------+---------+---------+----------------+", // 2
"\r\n s : SETTING d : DIAGNOSTIC " // 3
};
void AfemodeScreen(void)
{
for (int i = 0; i < 22; i++)
{
printf("%s", AfeMODE_STR[i]);
delay_os_ms(2);
}
}
int dis_numberOfCells;
uint8_t dis_AfeStatus;
uint8_t dis_AfeCtrl1;
uint8_t dis_AfeCtrl2;
uint8_t dis_AfeUvTrip;
uint8_t dis_AfeOvTrip;
uint8_t dis_AfeProtect[3];
//int dis_cellVoltages[MAX_NUMBER_OF_CELLS]; // mV
//uint32_t dis_batVoltage; // mV
//int dis_temperatures[MAX_NUMBER_OF_THERMISTORS]; //
//uint8_t dis_balStatus[3];
//int dis_adcGain = 0; // uV/LSB
//int dis_adcOffset = 0; // mV
//extern int adcGain; // uV/LSB
//extern int adcOffset; // mV
//void AfeDisplayStatus(uint8_t p)
//{
// uint8_t text[20];
// uint32_t sts = 0;
//
// sts = getAfeStatus();
// if (p || (dis_AfeStatus != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(35, 12, text);
// dis_AfeStatus = sts;
// }
// sts = getAfeCtrl1();
// if (p || (dis_AfeCtrl1 != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(35, 13, text);
// dis_AfeCtrl1 = sts;
// }
// sts = getAfeCtrl2();
// if (p || (dis_AfeCtrl2 != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(35, 14, text);
// dis_AfeCtrl2 = sts;
// }
//
// for (int i = 0; i < 3; i++)
// {
// sts = getAfeProtect(i);
// if (p || (dis_AfeProtect[i] != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(29 + (i * 3), 15, text);
// dis_AfeProtect[i] = sts;
// }
// }
//
// sts = getAfeUvTrip();
// if (p || (dis_AfeUvTrip != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(55, 12, text);
// dis_AfeUvTrip = sts;
// }
// sts = getAfeOvTrip();
// if (p || (dis_AfeOvTrip != sts))
// {
// sprintf((char *)text, "%02X", sts);
// GreenOutXY(55, 13, text);
// dis_AfeOvTrip = sts;
// }
//
// sts = getBatteryVoltage();
// if (p || (dis_batVoltage != sts))
// {
// sprintf((char *)text, "%6.3f", (float)sts / 1000);
// GreenOutXY(51, 14, text);
// dis_batVoltage = sts;
// }
//
// for (int i = 0; i < 3; i++)
// {
// if (p || (dis_device_value.SectVoltage[i] != device_value.SectVoltage[i]))
// {
// sprintf((char *)text, "%7.3f", (float)device_value.SectVoltage[i] / 1000);
// GreenOutXY(38 + (i * 7), 15, text);
// dis_device_value.SectVoltage[i] = device_value.SectVoltage[i];
// }
// }
//
// if (p || (dis_adcGain != adcGain))
// {
// sprintf((char *)text, "%04X", adcGain);
// GreenOutXY(32, 16, text);
// dis_adcGain = adcGain;
// }
// if (p || (dis_adcOffset != adcOffset))
// {
// sprintf((char *)text, "%04X", adcOffset);
// GreenOutXY(40, 16, text);
// dis_adcOffset = adcOffset;
// }
//}
uint8_t AfeSetBal(uint8_t *text, uint8_t aDevice)
{
uint16_t size, i, j;
int32_t aParam[4];
uint8_t temp[10];
uint8_t ret;
ret = 0;
size = 0;
while (text[size] != 0x00) size++; /* Measure total string length */
switch (aDevice) {
case '0' : // Cell Balance Parameter Setting
i = 0;
if (size < 1 ) return(1);
j = FIND_CHAR((uint8_t *)&text[i], temp, size - i, ' ');
i = i + j + 1;
temp[j] = 0x00;
aParam[0] = StrToInt(temp, j);
// SetManualBalancing(true, aParam[0]);
break;
case '1': // Cellbal off
// SetManualBalancing(false, text[2] - 0x30);
break;
default:
ret = 1;
break;
}
return(ret); /* Setting value OK */
}
/* Command processing in SETTING STATE */
int8_t Process_DataAfeModeSet(uint8_t *text, uint16_t size)
{
uint16_t i, ret;
/* Invalid command if space is in first position */
if (size > 1) {if (text[1] != ' ') return(0);}
text[size] = 0x00;
ret = 1;
switch (text[0])
{
case 'o': /* Switch to operating mode */
screenmode = OP_MODE;
ViewScreen();
break;
case 's': /* Switch to setting status */
screenmode = SET_MODE;
ViewScreen();
break;
case 'd': /* Switch to diagnostic mode */
screenmode = DIAG_MODE;
ViewScreen();
break;
case '0': // OCV Alarm Parameter Setting
case '1': // OCV Alarm Parameter Setting
i = AfeSetBal(&text[2], text[0]);
if (i == 0)
UserMessage("COMMAND COMPLETE");
else if (i == 1)
UserMessage("COMMAND FORMAT ERROR"); /* setting format error */
else
UserMessage("COMMAND LIMIT ERROR"); /* setting limit error */
break;
default :
ret = 0;
break;
}
return(ret);
}
#endif // #ifdef CONSOLE_DEBUG
/*******************(C)COPYRIGHT 2022 AMG ********************END OF FILE******/