981 lines
26 KiB
C
981 lines
26 KiB
C
/**
|
|
******************************************************************************
|
|
* @file afe_comm.c
|
|
* @author AMG Energy Solution Team
|
|
* @version V1.0.0
|
|
* @date 07-Feb-2022
|
|
* @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>© COPYRIGHT 2022 AMG</center></h2>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/** @addtogroup mBMS2
|
|
* @{
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include <includes.h>
|
|
#include "afe_comm.h"
|
|
#include "usart.h"
|
|
#include "i2c.h"
|
|
#include "asutil.h"
|
|
#include "malloc.h"
|
|
#include "delay.h"
|
|
#include "device_param.h"
|
|
#include "brtc.h"
|
|
#include "console.h"
|
|
#include "bq769x0.h"
|
|
#include "io.h"
|
|
|
|
/* Private define ------------------------------------------------------------*/
|
|
#define AFE_COMM_TASK_TIME 100 // 50ms TASK
|
|
|
|
#define PACK_BUF_MAX 20
|
|
|
|
/* Private typedef -----------------------------------------------------------*/
|
|
typedef struct
|
|
{
|
|
uint32_t Tick;
|
|
uint16_t Timeout;
|
|
uint8_t Commfail;
|
|
uint8_t Init;
|
|
} TAfeCommState, *PAfeCommState;
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t cVolt[DEVICE_MAX_CELL + 1];
|
|
} TPackBuf, *PPackBuf;
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t cell_fail : 1;
|
|
uint16_t ocv_alarm : 1;
|
|
uint16_t ocv_shutdown : 1;
|
|
uint16_t odv_alarm : 1;
|
|
uint16_t odv_shutdown : 1;
|
|
uint16_t cell_balance : 1;
|
|
uint16_t reserved : 10;
|
|
} TCellAlarm, *PCellAlarm;
|
|
|
|
typedef struct _TCellData
|
|
{
|
|
uint16_t volt;
|
|
TCellAlarm alarm;
|
|
} TCellData, *PCellData;
|
|
|
|
/* Private macro -------------------------------------------------------------*/
|
|
|
|
/* Private variables ---------------------------------------------------------*/
|
|
TAfeCommState AfeCommState;
|
|
|
|
uint16_t PackBufCh = 0;
|
|
TPackBuf PackBuf[PACK_BUF_MAX];
|
|
|
|
uint32_t Balance_Avg, disBalance_Avg;
|
|
uint8_t disCellBalancingFlag;
|
|
uint8_t CellBalancingMode = 0; // 0: even, 1: odd
|
|
|
|
uint16_t setBalValue = 0;
|
|
|
|
uint8_t CB_Rest = false;
|
|
uint32_t CB_Tick = 0;
|
|
uint32_t disCB_Tick = 0;
|
|
|
|
uint16_t ManualBalValue = 0;
|
|
uint8_t ManualBalFlag = 0;
|
|
|
|
uint8_t Afe_ShutDonwFlag = 0;
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
void AfeCommProcess(void);
|
|
void AfeUpdateData(void);
|
|
|
|
void CellVoltagePutBuf(void);
|
|
void MakeCellAvgData(void);
|
|
|
|
void Cell_AutoBalancing(uint32_t rBal);
|
|
void Cell_ManualBalancing(uint32_t rBal);
|
|
|
|
/* Private functions ---------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Initialize for AFE (Analog Front End) Communication
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void AfeCommInit(void)
|
|
{
|
|
bq769x0_construct();
|
|
|
|
memset(&AfeCommState, 0x00, sizeof(TAfeCommState));
|
|
|
|
device_status.battery_status.bit.ACB = true;
|
|
|
|
bq769x0_begin(0, 0);
|
|
}
|
|
|
|
/**
|
|
* @brief Application Task for AFE (Analog Front End) Communication
|
|
* @param None
|
|
* @retval None
|
|
*/
|
|
void App_TaskAfeComm(void)
|
|
{
|
|
AfeCommInit();
|
|
|
|
while (DEF_TRUE)
|
|
{
|
|
if (Afe_ShutDonwFlag == true)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
AfeCommProcess();
|
|
AfeUpdateData();
|
|
|
|
if (DIDState(2) == cOCCUR)
|
|
{
|
|
bq769x0_ResetAlert();
|
|
}
|
|
}
|
|
delay_os_ms(AFE_COMM_TASK_TIME);
|
|
}
|
|
}
|
|
|
|
void AfeUpdateData(void)
|
|
{
|
|
device_value.Heartbeat = OptimeStamp;
|
|
device_status.battery_status.bit.AFE = AfeCommState.Commfail;
|
|
}
|
|
|
|
uint8_t BuffFlag = true;
|
|
|
|
void AfeCommProcess(void)
|
|
{
|
|
uint32_t rTmp = 0;
|
|
|
|
bq769x0_updateData();
|
|
|
|
CellVoltagePutBuf();
|
|
MakeCellAvgData();
|
|
|
|
rTmp = getCellBalStatus();
|
|
|
|
if (device_status.battery_status.bit.ACB) {
|
|
Cell_AutoBalancing(rTmp);
|
|
} else {
|
|
Cell_ManualBalancing(rTmp);
|
|
}
|
|
}
|
|
|
|
void CellVoltagePutBuf(void)
|
|
{
|
|
uint32_t nCells, ch, tmp, sectSum[3];
|
|
uint32_t adcGain2 = device_calib_data.cal.voltage.BatV_Gain;
|
|
|
|
ch = PackBufCh;
|
|
nCells = getNumberOfCells();
|
|
|
|
for (int i = 0; i < nCells; i++) {
|
|
tmp = getCellVoltage(i + 1) * adcGain2 / 10000;
|
|
PackBuf[ch].cVolt[i] = tmp; // Cell 15
|
|
}
|
|
|
|
if (BuffFlag == true) {
|
|
BuffFlag = false;
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
|
|
for (int k = 0; k < PACK_BUF_MAX; k++) {
|
|
PackBuf[k].cVolt[i] = PackBuf[ch].cVolt[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cell Volt Avg
|
|
sectSum[0] = 0;
|
|
sectSum[1] = 0;
|
|
sectSum[2] = 0;
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
|
|
tmp = 0;
|
|
|
|
for (int k = 0; k < PACK_BUF_MAX; k++) {
|
|
tmp += PackBuf[k].cVolt[i];
|
|
}
|
|
device_value.Cell.voltage[i] = (uint16_t)(tmp / PACK_BUF_MAX);
|
|
sectSum[i / 5] += device_value.Cell.voltage[i];
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
device_value.SectVoltage[i] = sectSum[i];
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void dec_cb_tick(uint16_t tick)
|
|
{
|
|
if (CB_Tick > tick)
|
|
CB_Tick -= tick;
|
|
else
|
|
CB_Tick = 0;
|
|
}
|
|
|
|
void Cell_AutoBalancing1(uint32_t rBal)
|
|
{
|
|
uint16_t bal = 0;
|
|
uint8_t setBal = false;
|
|
PDEVICE_PARAM param = &device_param;
|
|
|
|
// for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
// {
|
|
// if ((rBal >> i) & 0x0001)
|
|
// {
|
|
// bal |= (uint16_t)(1 << i);
|
|
// }
|
|
// }
|
|
bal = rBal;
|
|
// device_status.cellbalance.value = bal;
|
|
|
|
if (CB_Rest == true)
|
|
{
|
|
if (CB_Tick == 0)
|
|
{
|
|
CB_Rest = false;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
setBal = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CB_Tick == 0)
|
|
{
|
|
CB_Rest = true;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
setBal = true;
|
|
}
|
|
}
|
|
|
|
if (device_status.battery_status.bit.CB == true)
|
|
{
|
|
// Before cell balancing status is ON
|
|
// if (device_value.Cell.avg.Max.value < param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold) {
|
|
if (device_value.Cell.avg.Max.value < 3400) {
|
|
device_status.battery_status.bit.CB = false;
|
|
setBalValue = 0;
|
|
} 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) {
|
|
device_status.battery_status.bit.CB = false;
|
|
setBalValue = 0;
|
|
}
|
|
}
|
|
} 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.Max.value > 3450) {
|
|
if (device_value.Cell.avg.diff > param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min) {
|
|
device_status.battery_status.bit.CB = true;
|
|
} else if (device_status.warning.bit.cell_over_voltage) {
|
|
device_status.battery_status.bit.CB = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (device_status.battery_status.bit.CB == true)
|
|
{
|
|
if (setBal == true)
|
|
{
|
|
if (CB_Rest == false)
|
|
{
|
|
if (device_value.Cell.avg.Max.value > device_param.chg_ctrl.term_cfg.CB_Limit_Voltage)
|
|
{
|
|
Balance_Avg = device_param.chg_ctrl.term_cfg.CB_Limit_Voltage;
|
|
}
|
|
else if (device_value.Cell.avg.Min.value > 3580)
|
|
{
|
|
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > 20)
|
|
{
|
|
Balance_Avg = device_value.Cell.avg.avg + 10;
|
|
}
|
|
else
|
|
{
|
|
if ((device_value.Cell.avg.avg - device_value.Cell.avg.Min.value) > 20)
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_Avg = device_value.Cell.avg.avg + 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 20;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 15;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 10;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 5;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 1;
|
|
else
|
|
Balance_Avg = device_value.Cell.avg.avg - 1;
|
|
}
|
|
else
|
|
{
|
|
Balance_Avg = device_value.Cell.avg.avg;
|
|
}
|
|
}
|
|
|
|
if (Balance_Avg < 3350) Balance_Avg = 3600;
|
|
|
|
bal = 0;
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
if (device_value.Cell.voltage[i] > Balance_Avg)
|
|
{
|
|
bal = bal | (1 << i);
|
|
}
|
|
else if ((device_value.Cell.voltage[i] > 3350) && ((device_status.cov_warning_cell.uValue >> i) == 1))
|
|
{
|
|
bal = bal | (1 << i);
|
|
}
|
|
// else if ((device_value.Cell.voltage[i] > Balance_Avg) || ((device_status.cov_warning_cell.uValue >> i) == 1))
|
|
// {
|
|
// bal = bal | (1 << i);
|
|
// }
|
|
}
|
|
setBalValue = bal;
|
|
// bq769x0_updateBalancingSwitches(setBalValue, CellBalancingMode);
|
|
bq769x0_updateBalancingSwitches(setBalValue, 0);
|
|
// if (CellBalancingMode == 0) CellBalancingMode = 1; else CellBalancingMode = 0;
|
|
}
|
|
else
|
|
{
|
|
// CB Rest time
|
|
bal = setBalValue;
|
|
// for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
// {
|
|
// if ((device_status.cov_warning_cell.uValue >> i) == 1)
|
|
// {
|
|
// bal = bal | (1 << i);
|
|
// }
|
|
// }
|
|
bq769x0_updateBalancingSwitches(bal, 1);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bal != 0x0000)
|
|
{
|
|
setBalValue = 0;
|
|
bq769x0_updateBalancingSwitches(setBalValue, 0);
|
|
}
|
|
}
|
|
device_status.cellbalance.value = setBalValue;
|
|
}
|
|
|
|
void Cell_AutoBalancing(uint32_t rBal)
|
|
{
|
|
uint16_t bal = 0;
|
|
uint8_t setBal = false;
|
|
PDEVICE_PARAM param = &device_param;
|
|
|
|
bal = rBal;
|
|
|
|
switch (CB_Rest)
|
|
{
|
|
case 0:
|
|
if (CB_Tick == 0) {
|
|
CB_Rest = 1;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
setBal = true;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (CB_Tick == 0) {
|
|
if ((device_value.Cell.avg.Min.value > 3500) && (device_value.Cell.avg.diff < 15)) {
|
|
CB_Rest = 2;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000 * 3;
|
|
} else {
|
|
CB_Rest = 0;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
}
|
|
setBal = true;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (CB_Tick == 0) {
|
|
CB_Rest = 0;
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
setBal = true;
|
|
}
|
|
break;
|
|
default:
|
|
CB_Rest = 0;
|
|
break;
|
|
}
|
|
|
|
if (device_status.battery_status.bit.CB == true)
|
|
{
|
|
// Before cell balancing status is ON
|
|
if (device_value.Cell.avg.Max.value < param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold) {
|
|
device_status.battery_status.bit.CB = false;
|
|
setBalValue = 0;
|
|
}
|
|
else if (device_value.Cell.avg.diff < (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min - 3))
|
|
{
|
|
if (device_status.warning.bit.cell_over_voltage == 0) {
|
|
device_status.battery_status.bit.CB = false;
|
|
setBalValue = 0;
|
|
}
|
|
}
|
|
}
|
|
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)
|
|
device_status.battery_status.bit.CB = true;
|
|
else if (device_status.warning.bit.cell_over_voltage)
|
|
device_status.battery_status.bit.CB = true;
|
|
}
|
|
}
|
|
|
|
if (device_status.battery_status.bit.CB == true)
|
|
{
|
|
if (setBal == true)
|
|
{
|
|
switch (CB_Rest) {
|
|
case 0:
|
|
if (device_value.Cell.avg.Max.value > device_param.chg_ctrl.term_cfg.CB_Limit_Voltage)
|
|
{
|
|
Balance_Avg = device_param.chg_ctrl.term_cfg.CB_Limit_Voltage;
|
|
}
|
|
else if (device_value.Cell.avg.Min.value > 3580)
|
|
{
|
|
if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > 20)
|
|
{
|
|
Balance_Avg = device_value.Cell.avg.avg + 10;
|
|
}
|
|
else
|
|
{
|
|
if ((device_value.Cell.avg.avg - device_value.Cell.avg.Min.value) > 20)
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_Avg = device_value.Cell.avg.avg + 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 20;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 15;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 10;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 5;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 2;
|
|
else
|
|
Balance_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))
|
|
Balance_Avg = device_value.Cell.avg.avg + 1;
|
|
else
|
|
Balance_Avg = device_value.Cell.avg.avg - 1;
|
|
}
|
|
else
|
|
{
|
|
Balance_Avg = device_value.Cell.avg.avg;
|
|
}
|
|
}
|
|
|
|
if (Balance_Avg < 3350) Balance_Avg = 3600;
|
|
|
|
bal = 0;
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
if (device_value.Cell.voltage[i] > Balance_Avg)
|
|
{
|
|
bal = bal | (1 << i);
|
|
}
|
|
else if ((device_value.Cell.voltage[i] > 3350) && ((device_status.cov_warning_cell.uValue >> i) == 1))
|
|
{
|
|
bal = bal | (1 << i);
|
|
}
|
|
// else if ((device_value.Cell.voltage[i] > Balance_Avg) || ((device_status.cov_warning_cell.uValue >> i) == 1))
|
|
// {
|
|
// bal = bal | (1 << i);
|
|
// }
|
|
}
|
|
setBalValue = bal;
|
|
bq769x0_updateBalancingSwitches(setBalValue, 0);
|
|
break;
|
|
case 1:
|
|
// CB Rest time
|
|
bal = setBalValue;
|
|
bq769x0_updateBalancingSwitches(bal, 1);
|
|
break;
|
|
case 2:
|
|
setBalValue = 0;
|
|
bal = setBalValue;
|
|
bq769x0_updateBalancingSwitches(bal, 1);
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
if ((device_status.cov_warning_cell.uValue >> i) == 1)
|
|
{
|
|
bal = bal | (1 << i);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
CB_Rest = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bal != 0x0000)
|
|
{
|
|
setBalValue = 0;
|
|
bq769x0_updateBalancingSwitches(setBalValue, 0);
|
|
}
|
|
}
|
|
device_status.cellbalance.value = setBalValue;
|
|
}
|
|
|
|
void SetManualBalancing(uint8_t flag, uint32_t cNo)
|
|
{
|
|
ManualBalFlag = flag;
|
|
|
|
if (ManualBalFlag == true)
|
|
{
|
|
device_status.battery_status.bit.ACB = false;
|
|
if (cNo >= 1)
|
|
ManualBalValue |= (1 << (cNo - 1));
|
|
}
|
|
else
|
|
{
|
|
device_status.battery_status.bit.ACB = true;
|
|
ManualBalValue = 0;
|
|
}
|
|
}
|
|
|
|
void Cell_ManualBalancing(uint32_t rBal)
|
|
{
|
|
uint16_t bal = 0;
|
|
PDEVICE_PARAM param = &device_param;
|
|
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++) {
|
|
if ((rBal >> i) & 0x0001) {
|
|
bal |= (uint16_t)(1 << i);
|
|
}
|
|
}
|
|
device_status.cellbalance.value = bal;
|
|
|
|
if (ManualBalFlag == true) {
|
|
if (CB_Tick == 0) {
|
|
CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000;
|
|
if (CellBalancingMode == 0) CellBalancingMode = 1; else CellBalancingMode = 0;
|
|
}
|
|
// if (ManualBalValue != bal)
|
|
bq769x0_updateBalancingSwitches(ManualBalValue, CellBalancingMode);
|
|
}
|
|
else
|
|
{
|
|
if (bal != 0)
|
|
bq769x0_updateBalancingSwitches(0, 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******/
|