1097 lines
28 KiB
C
1097 lines
28 KiB
C
/* Copyright (c) 2012-2013 The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* High Level description:
|
|
* http://www.ti.com/lit/ds/symlink/bq28400.pdf
|
|
* Thechnical Reference:
|
|
* http://www.ti.com/lit/ug/sluu431/sluu431.pdf
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "dflash_sf1.h"
|
|
#include "device_param.h"
|
|
#include "asutil.h"
|
|
#include "console.h"
|
|
#include "PL455_comm.h"
|
|
#include "temp.h"
|
|
#include "vi.h"
|
|
|
|
#define SLEEP_VOLTAGE 4200
|
|
#define WAKEUP_VOLTAGE 4500
|
|
#define SLEEP_MODE_TIME 60 * 1000
|
|
#define CELL_DEVIATION_CHECK_VOLTAGE 4500
|
|
|
|
#define OCC_CRITICAL_CLEAR_TIME 60 * 1000
|
|
|
|
#define PRECHARGE_TIME_DEFAULT 2 * 1000
|
|
#define CV_DIFF_PROTECT_HOLD_TIME (24UL * 60UL * 60UL * 1000UL) // 24 hours in ms
|
|
#define TEMP_DIFF_PROTECT_THRESHOLD 30 // 3.0C (0.1C unit)
|
|
#define TEMP_DIFF_PROTECT_HOLD_TIME (24UL * 60UL * 60UL * 1000UL) // 24 hours in ms
|
|
|
|
u8 SleepMode = false;
|
|
u32 smode_tick = 60 * 1000;
|
|
|
|
u32 PreChargeTime = PRECHARGE_TIME_DEFAULT;
|
|
u32 OCCTime = 0;
|
|
u32 OCDTime = 0;
|
|
|
|
u32 CV_Diff_ProtectTime = CV_DIFF_PROTECT_HOLD_TIME;
|
|
u32 CV_Diff_ProtectHoldTime = CV_DIFF_PROTECT_HOLD_TIME; // Default: 24 hours (configurable in RAM)
|
|
|
|
u32 Temp_Diff_ProtectTime = TEMP_DIFF_PROTECT_HOLD_TIME;
|
|
u32 Temp_Diff_ProtectHoldTime = TEMP_DIFF_PROTECT_HOLD_TIME;
|
|
u16 Temp_Diff_Threshold = TEMP_DIFF_PROTECT_THRESHOLD; // Default: 30 (3.0 deg C)
|
|
|
|
s32 OCC_Occur_Current;
|
|
s32 OCD_Occur_Current;
|
|
|
|
u32 OCC_CRITICAL_Tick = 60 * 1000;
|
|
u8 OCC_Fail_Count = 0;
|
|
u8 OCC_3Times_Fail = false;
|
|
|
|
void dec_precharge_time(u32 tick);
|
|
void dec_occ_time(u32 tick);
|
|
void dec_occ_critical_time(u32 tick);
|
|
void dec_ocd_time(u32 tick);
|
|
void dec_sleepmode_time(u32 tick);
|
|
void dec_cv_diff_time(u32 tick);
|
|
void dec_temp_diff_time(u32 tick);
|
|
|
|
void ProcessSafety_COV(void);
|
|
void ProcessSafety_CUV(void);
|
|
void ProcessSafety_OTA(void);
|
|
void ProcessSafety_LTA(void);
|
|
void ProcessSafety_OCC(void);
|
|
void ProcessSafety_OCD(void);
|
|
void ProcessSafety_SOC(void);
|
|
void ProcessSafety_CellVoltageDiff(void);
|
|
void ProcessSafety_TempDiff(void);
|
|
|
|
void Process_FetControl(void);
|
|
void ProcessStatusCheck(void);
|
|
|
|
|
|
void ClearODCTick(void)
|
|
{
|
|
OCDTime = device_param.safety.current.OC_Dsg_Rec_Time * 1000;
|
|
}
|
|
|
|
void dec_alarm_tick(u32 tick)
|
|
{
|
|
dec_precharge_time(tick);
|
|
dec_occ_time(tick);
|
|
dec_occ_critical_time(tick);
|
|
dec_ocd_time(tick);
|
|
dec_cv_diff_time(tick);
|
|
dec_temp_diff_time(tick);
|
|
dec_sleepmode_time(tick);
|
|
}
|
|
|
|
void dec_sleepmode_time(u32 tick)
|
|
{
|
|
if (smode_tick > 0)
|
|
{
|
|
if (smode_tick > tick)
|
|
smode_tick -= tick;
|
|
else
|
|
smode_tick = 0;
|
|
}
|
|
}
|
|
|
|
u8 GetSleepMode(void)
|
|
{
|
|
return SleepMode;
|
|
}
|
|
|
|
void SetSleepMode(u8 mode)
|
|
{
|
|
SleepMode = mode;
|
|
}
|
|
|
|
void CheckSleepMode(void)
|
|
{
|
|
if (SleepMode == true)
|
|
{
|
|
if (device_status.op_status == 1)
|
|
{
|
|
SleepMode = false;
|
|
smode_tick = SLEEP_MODE_TIME;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((device_status.protection.bit.cell_under_voltage) || (device_status.protection.bit.under_voltage))
|
|
{
|
|
if (smode_tick == 0)
|
|
SleepMode = true;
|
|
}
|
|
else
|
|
{
|
|
smode_tick = SLEEP_MODE_TIME;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProcessAlarm(void)
|
|
{
|
|
if (device_status.battery_status.bit.INIT)
|
|
{
|
|
device_status.protection.bit.afe_fail = device_status.battery_status.bit.AFE | device_status.error.bit.afe_fail;
|
|
|
|
if (device_status.battery_status.bit.AFE == false)
|
|
{
|
|
ProcessSafety_COV();
|
|
ProcessSafety_CUV();
|
|
}
|
|
ProcessSafety_OTA();
|
|
ProcessSafety_LTA();
|
|
ProcessSafety_OCC();
|
|
ProcessSafety_OCD();
|
|
ProcessSafety_SOC();
|
|
ProcessSafety_CellVoltageDiff();
|
|
ProcessSafety_TempDiff();
|
|
|
|
Process_FetControl();
|
|
|
|
CheckSleepMode();
|
|
}
|
|
ProcessStatusCheck();
|
|
}
|
|
|
|
void dec_precharge_time(u32 tick)
|
|
{
|
|
if (PreChargeTime > 0)
|
|
{
|
|
if (PreChargeTime > tick)
|
|
PreChargeTime -= tick;
|
|
else
|
|
PreChargeTime = 0;
|
|
}
|
|
}
|
|
|
|
void ProcessSafety_COV(void)
|
|
{
|
|
/* Cell Over Voltage Check */
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
/* Cell Over Voltage Protection */
|
|
if (device_status.cov_protection_cell.uValue & BIT(i))
|
|
{
|
|
// Release check
|
|
if (device_value.Cell.voltage[i] < device_param.safety.voltage.COV_Recovery)
|
|
device_status.cov_protection_cell.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Alarm check
|
|
if (device_value.Cell.voltage[i] > device_param.safety.voltage.COV_Threshold)
|
|
device_status.cov_protection_cell.uValue |= BIT(i);
|
|
}
|
|
/* Cell Over Voltage Warning */
|
|
if (device_status.cov_warning_cell.uValue & BIT(i))
|
|
{
|
|
// Release check
|
|
if (device_value.Cell.voltage[i] < device_param.safety.voltage.COV_Recovery)
|
|
device_status.cov_warning_cell.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Alarm check
|
|
if (device_value.Cell.voltage[i] > device_param.safety.voltage.COV_Warning)
|
|
device_status.cov_warning_cell.uValue |= BIT(i);
|
|
}
|
|
}
|
|
if (device_status.cov_protection_cell.uValue != 0)
|
|
device_status.protection.bit.cell_over_voltage = true;
|
|
else
|
|
device_status.protection.bit.cell_over_voltage = false;
|
|
|
|
if (device_status.cov_warning_cell.uValue != 0)
|
|
device_status.warning.bit.cell_over_voltage = true;
|
|
else
|
|
device_status.warning.bit.cell_over_voltage = false;
|
|
|
|
|
|
/* System Over charge protection */
|
|
if (device_status.protection.bit.over_voltage)
|
|
{
|
|
// Release check
|
|
if (device_value.BatVoltage < device_param.safety.voltage.SOV_Recovery)
|
|
device_status.protection.bit.over_voltage = false;
|
|
}
|
|
else
|
|
{
|
|
// Alarm check
|
|
if (device_value.BatVoltage > device_param.safety.voltage.SOV_Threshold)
|
|
device_status.protection.bit.over_voltage = true;
|
|
}
|
|
|
|
/* System Over Voltage Warning */
|
|
if (device_status.warning.bit.over_voltage)
|
|
{
|
|
// Release check
|
|
if (device_value.BatVoltage < device_param.safety.voltage.SOV_Recovery)
|
|
device_status.warning.bit.over_voltage = false;
|
|
} else {
|
|
// Alarm check
|
|
if (device_value.BatVoltage > device_param.safety.voltage.SOV_Warning)
|
|
device_status.warning.bit.over_voltage = true;
|
|
}
|
|
}
|
|
|
|
void ProcessSafety_CUV(void)
|
|
{
|
|
/* Cell under voltage check */
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
/* Cell under voltage protection */
|
|
if (device_status.cuv_protection_cell.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (device_value.Cell.voltage[i] > device_param.safety.voltage.CUV_Recovery)
|
|
device_status.cuv_protection_cell.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Protection Check
|
|
if (device_value.Cell.voltage[i] < device_param.safety.voltage.CUV_Threshold)
|
|
device_status.cuv_protection_cell.uValue |= BIT(i);
|
|
}
|
|
|
|
/* Cell under voltage warning */
|
|
if (device_status.cuv_warning_cell.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (device_value.Cell.voltage[i] > device_param.safety.voltage.CUV_Recovery)
|
|
device_status.cuv_warning_cell.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Warning Check
|
|
if (device_value.Cell.voltage[i] < device_param.safety.voltage.CUV_Warning)
|
|
device_status.cuv_warning_cell.uValue |= BIT(i);
|
|
}
|
|
}
|
|
|
|
if (device_status.cuv_protection_cell.uValue != 0)
|
|
device_status.protection.bit.cell_under_voltage = true;
|
|
else
|
|
device_status.protection.bit.cell_under_voltage = false;
|
|
|
|
if (device_status.cuv_warning_cell.uValue != 0)
|
|
device_status.warning.bit.cell_under_voltage = true;
|
|
else
|
|
device_status.warning.bit.cell_under_voltage = false;
|
|
|
|
/* Cell Voltage Fault Check (Below 1000mV or above 4500mV abnormal voltage cutoff charging) */
|
|
uint8_t cell_fault = false;
|
|
for (int i = 0; i < DEVICE_MAX_CELL; i++)
|
|
{
|
|
if ((device_value.Cell.voltage[i] <= 1000) || (device_value.Cell.voltage[i] >= 4500))
|
|
{
|
|
cell_fault = true;
|
|
break;
|
|
}
|
|
}
|
|
if (cell_fault)
|
|
{
|
|
device_status.error.bit.afe_fail = true;
|
|
device_status.protection.bit.afe_fail = true;
|
|
}
|
|
else
|
|
{
|
|
device_status.error.bit.afe_fail = false;
|
|
}
|
|
|
|
/* System under voltage protection */
|
|
if (device_status.protection.bit.under_voltage)
|
|
{
|
|
// Release check
|
|
if (device_value.BatVoltage > device_param.safety.voltage.SUV_Recovery)
|
|
device_status.protection.bit.under_voltage = false;
|
|
}
|
|
else
|
|
{
|
|
// Alarm check
|
|
if (device_value.BatVoltage < device_param.safety.voltage.SUV_Threshold)
|
|
device_status.protection.bit.under_voltage = true;
|
|
}
|
|
|
|
/* System under voltage warning */
|
|
if (device_status.warning.bit.under_voltage)
|
|
{
|
|
// Release check
|
|
if (device_value.BatVoltage > device_param.safety.voltage.SUV_Recovery)
|
|
device_status.warning.bit.under_voltage = false;
|
|
}
|
|
else
|
|
{
|
|
// Alarm check
|
|
if (device_value.BatVoltage < device_param.safety.voltage.SUV_Warning)
|
|
device_status.warning.bit.under_voltage = true;
|
|
}
|
|
|
|
if (device_status.protection.bit.under_voltage)
|
|
{
|
|
if (device_status.op_status == 0x0001)
|
|
{
|
|
device_status.protection.bit.under_voltage = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProcessSafety_OTA(void)
|
|
{
|
|
/* Temperature Sensor Fault Check */
|
|
if (IsTempSensorFailed())
|
|
{
|
|
device_status.error.bit.temp_sensor = true;
|
|
}
|
|
else
|
|
{
|
|
device_status.error.bit.temp_sensor = false;
|
|
}
|
|
/* Charge High Temperature */
|
|
for (int i = 0; i < DEVICE_MAX_TEMP; i++)
|
|
{
|
|
if (ADState(i) != AD_FAIL)
|
|
{
|
|
s16 aTemp = device_value.Temp.temperature[i];
|
|
|
|
/* Over Temperature Charge Protection */
|
|
if (device_status.otc_protection_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp < device_param.safety.temperature.OT_Chg_Recovery)
|
|
device_status.otc_protection_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Protection Check, when charging
|
|
if (device_status.battery_status.bit.MD == 0)
|
|
{
|
|
if (aTemp > device_param.safety.temperature.OT_Chg_Threshold)
|
|
device_status.otc_protection_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
/* Over Temperature Charge Warning */
|
|
if (device_status.otc_warning_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp < device_param.safety.temperature.OT_Chg_Recovery)
|
|
device_status.otc_warning_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Warning Check, when charging
|
|
if (device_status.battery_status.bit.MD == 0)
|
|
{
|
|
if (aTemp > device_param.safety.temperature.OT_Chg_Warning)
|
|
device_status.otc_warning_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* OTC Protection */
|
|
if (device_status.otc_protection_temp.uValue != 0)
|
|
device_status.protection.bit.chg_high_temp = true;
|
|
else
|
|
device_status.protection.bit.chg_high_temp = false;
|
|
|
|
/* OTC Warning */
|
|
if (device_status.otc_warning_temp.uValue != 0)
|
|
device_status.warning.bit.chg_high_temp = true;
|
|
else
|
|
device_status.warning.bit.chg_high_temp = false;
|
|
|
|
/* High Temperature Discharge */
|
|
for (int i = 0; i < DEVICE_MAX_TEMP; i++)
|
|
{
|
|
if (ADState(i) != AD_FAIL)
|
|
{
|
|
s16 aTemp = device_value.Temp.temperature[i];
|
|
|
|
/* Over Temperature Discharge Protection */
|
|
if (device_status.otd_protection_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp < device_param.safety.temperature.OT_Dsg_Recovery)
|
|
device_status.otd_protection_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Protection Check, when charging
|
|
if (device_status.battery_status.bit.MD == 1)
|
|
{
|
|
if (aTemp > device_param.safety.temperature.OT_Dsg_Threshold)
|
|
device_status.otd_protection_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
/* Over Temperature Charge Warning */
|
|
if (device_status.otd_warning_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp < device_param.safety.temperature.OT_Dsg_Recovery)
|
|
device_status.otd_warning_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Warning Check, when charging
|
|
if (device_status.battery_status.bit.MD == 1)
|
|
{
|
|
if (aTemp > device_param.safety.temperature.OT_Dsg_Warning)
|
|
device_status.otd_warning_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* OTD Protection */
|
|
if (device_status.otd_protection_temp.uValue != 0)
|
|
device_status.protection.bit.dsg_high_temp = true;
|
|
else
|
|
device_status.protection.bit.dsg_high_temp = false;
|
|
|
|
/* OTD Warning */
|
|
if (device_status.otd_warning_temp.uValue != 0)
|
|
device_status.warning.bit.dsg_high_temp = true;
|
|
else
|
|
device_status.warning.bit.dsg_high_temp = false;
|
|
}
|
|
|
|
void ProcessSafety_LTA(void)
|
|
{
|
|
/* Charge Low Temperature */
|
|
for (int i = 0; i < DEVICE_MAX_TEMP; i++)
|
|
{
|
|
if (ADState(i) != AD_FAIL)
|
|
{
|
|
s16 aTemp = device_value.Temp.temperature[i];
|
|
|
|
/* Over Temperature Charge Protection */
|
|
if (device_status.ltc_protection_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp > device_param.safety.temperature.LT_Chg_Recovery)
|
|
device_status.ltc_protection_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Protection Check, when charging
|
|
if (device_status.battery_status.bit.MD == 0)
|
|
{
|
|
if (aTemp < device_param.safety.temperature.LT_Chg_Threshold)
|
|
device_status.ltc_protection_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
/* Low Temperature Charge Warning */
|
|
if (device_status.ltc_warning_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp > device_param.safety.temperature.LT_Chg_Recovery)
|
|
device_status.ltc_warning_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Warning Check, when charging
|
|
if (device_status.battery_status.bit.MD == 0)
|
|
{
|
|
if (aTemp < device_param.safety.temperature.LT_Chg_Warning)
|
|
device_status.ltc_warning_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* LTC Protection */
|
|
if (device_status.ltc_protection_temp.uValue != 0)
|
|
device_status.protection.bit.chg_low_temp = true;
|
|
else
|
|
device_status.protection.bit.chg_low_temp = false;
|
|
|
|
/* LTC Warning */
|
|
if (device_status.ltc_warning_temp.uValue != 0)
|
|
device_status.warning.bit.chg_low_temp = true;
|
|
else
|
|
device_status.warning.bit.chg_low_temp = false;
|
|
|
|
/* Low Temperature Discharge */
|
|
for (int i = 0; i < DEVICE_MAX_TEMP; i++)
|
|
{
|
|
if (ADState(i) != AD_FAIL)
|
|
{
|
|
s16 aTemp = device_value.Temp.temperature[i];
|
|
|
|
/* Low Temperature Discharge Protection */
|
|
if (device_status.ltd_protection_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp > device_param.safety.temperature.LT_Dsg_Recovery)
|
|
device_status.ltd_protection_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Protection Check, when charging
|
|
if (device_status.battery_status.bit.MD == 1)
|
|
{
|
|
if (aTemp < device_param.safety.temperature.LT_Dsg_Threshold)
|
|
device_status.ltd_protection_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
/* Over Temperature Charge Warning */
|
|
if (device_status.ltd_warning_temp.uValue & BIT(i))
|
|
{
|
|
// Recovery Check
|
|
if (aTemp > device_param.safety.temperature.LT_Dsg_Recovery)
|
|
device_status.ltd_warning_temp.uValue &= ~BIT(i);
|
|
}
|
|
else
|
|
{
|
|
// Warning Check, when charging
|
|
if (device_status.battery_status.bit.MD == 1)
|
|
{
|
|
if (aTemp < device_param.safety.temperature.LT_Dsg_Warning)
|
|
device_status.ltd_warning_temp.uValue |= BIT(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* LTD Protection */
|
|
if (device_status.ltd_protection_temp.uValue != 0)
|
|
device_status.protection.bit.dsg_low_temp = true;
|
|
else
|
|
device_status.protection.bit.dsg_low_temp = false;
|
|
|
|
/* LTD Warning */
|
|
if (device_status.ltd_warning_temp.uValue != 0)
|
|
device_status.warning.bit.dsg_low_temp = true;
|
|
else
|
|
device_status.warning.bit.dsg_low_temp = false;
|
|
}
|
|
|
|
void dec_occ_time(u32 tick)
|
|
{
|
|
if (OCCTime > 0)
|
|
{
|
|
if (OCCTime > tick)
|
|
OCCTime -= tick;
|
|
else
|
|
OCCTime = 0;
|
|
}
|
|
}
|
|
|
|
void dec_occ_critical_time(u32 tick)
|
|
{
|
|
if (OCC_CRITICAL_Tick > 0)
|
|
{
|
|
if (OCC_CRITICAL_Tick > tick)
|
|
OCC_CRITICAL_Tick -= tick;
|
|
else
|
|
OCC_CRITICAL_Tick = 0;
|
|
}
|
|
}
|
|
|
|
void ProcessSafety_OCC(void)
|
|
{
|
|
/* Over charge current protection */
|
|
if (device_status.protection.bit.chg_over_current)
|
|
{
|
|
// release check: DO NOT auto-recover if repeated OCC fail occurred (Latched)
|
|
if (OCC_3Times_Fail)
|
|
{
|
|
device_status.protection.bit.chg_over_current = true;
|
|
}
|
|
else
|
|
{
|
|
if ((device_value.Current / 1) < (device_param.safety.current.OC_Chg_Recovery * 10))
|
|
{
|
|
if (OCCTime == 0)
|
|
device_status.protection.bit.chg_over_current = false;
|
|
}
|
|
else
|
|
{
|
|
OCCTime = device_param.safety.current.OC_Chg_Rec_Time * 1000;
|
|
OCC_CRITICAL_Tick = OCC_CRITICAL_CLEAR_TIME;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// alarm check
|
|
if ((device_value.Current / 1) > (device_param.safety.current.OC_Chg_Threshold * 10))
|
|
{
|
|
OCC_Occur_Current = device_value.Current;
|
|
device_status.protection.bit.chg_over_current = true;
|
|
OCCTime = device_param.safety.current.OC_Chg_Rec_Time * 1000;
|
|
|
|
if (OCC_Fail_Count < 3)
|
|
{
|
|
OCC_Fail_Count++;
|
|
OCC_CRITICAL_Tick = OCC_CRITICAL_CLEAR_TIME;
|
|
}
|
|
if (OCC_Fail_Count >= 3)
|
|
{
|
|
OCC_3Times_Fail = true;
|
|
OCC_CRITICAL_Tick = OCC_CRITICAL_CLEAR_TIME;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OCC_3Times_Fail == false)
|
|
{
|
|
if (OCC_Fail_Count > 0)
|
|
{
|
|
if (OCC_CRITICAL_Tick == 0)
|
|
{
|
|
OCC_Fail_Count = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
device_status.battery_status.bit.TCA = OCC_3Times_Fail;
|
|
device_status.protection.bit.critial_over_current = OCC_3Times_Fail;
|
|
|
|
/* Over current charge warning */
|
|
if (device_status.warning.bit.chg_over_current)
|
|
{
|
|
// release check
|
|
if ((device_value.Current / 1) < (device_param.safety.current.OC_Chg_Recovery * 10))
|
|
device_status.warning.bit.chg_over_current = false;
|
|
}
|
|
else
|
|
{
|
|
// alarm check
|
|
if ((device_value.Current / 1) > (device_param.safety.current.OC_Chg_Warning * 10))
|
|
device_status.warning.bit.chg_over_current = true;
|
|
}
|
|
}
|
|
|
|
void dec_ocd_time(u32 tick)
|
|
{
|
|
if (OCDTime > tick)
|
|
OCDTime -= tick;
|
|
else
|
|
OCDTime = 0;
|
|
}
|
|
|
|
void ProcessSafety_OCD(void)
|
|
{
|
|
/* Over current discharge protection */
|
|
if (device_status.protection.bit.dsg_over_current)
|
|
{
|
|
// release check
|
|
if ((device_value.Current / 1) > (device_param.safety.current.OC_Dsg_Recovery * 10))
|
|
{
|
|
if (OCDTime == 0)
|
|
device_status.protection.bit.dsg_over_current = false;
|
|
}
|
|
else
|
|
OCDTime = device_param.safety.current.OC_Dsg_Rec_Time * 1000;
|
|
}
|
|
else
|
|
{
|
|
// alarm check
|
|
if ((device_value.Current / 1) < (device_param.safety.current.OC_Dsg_Threshold * 10))
|
|
{
|
|
OCD_Occur_Current = device_value.Current;
|
|
device_status.protection.bit.dsg_over_current = true;
|
|
OCDTime = device_param.safety.current.OC_Dsg_Rec_Time * 1000;
|
|
}
|
|
}
|
|
|
|
/* Over current discharge warning */
|
|
if (device_status.warning.bit.dsg_over_current)
|
|
{
|
|
// release check
|
|
if ((device_value.Current / 1) > (device_param.safety.current.OC_Dsg_Recovery * 10))
|
|
device_status.warning.bit.dsg_over_current = false;
|
|
}
|
|
else
|
|
{
|
|
// alarm check
|
|
if ((device_value.Current / 1) < (device_param.safety.current.OC_Dsg_Warning * 10))
|
|
device_status.warning.bit.dsg_over_current = true;
|
|
}
|
|
}
|
|
|
|
void ProcessSafety_SOC(void)
|
|
{
|
|
/* Low capacity warning */
|
|
if (device_status.warning.bit.low_capacity)
|
|
{
|
|
// release check
|
|
if ((device_value.RelativeStateOfCharge) > (device_param.safety.soc.Low_Soc_Recovery * 10))
|
|
device_status.warning.bit.low_capacity = false;
|
|
}
|
|
else
|
|
{
|
|
// alarm check
|
|
if ((device_value.RelativeStateOfCharge) < (device_param.safety.soc.Low_Soc_Warning * 10))
|
|
device_status.warning.bit.low_capacity = true;
|
|
}
|
|
}
|
|
|
|
void dec_cv_diff_time(u32 tick)
|
|
{
|
|
if (CV_Diff_ProtectTime > tick)
|
|
CV_Diff_ProtectTime -= tick;
|
|
else
|
|
CV_Diff_ProtectTime = 0;
|
|
}
|
|
|
|
u32 GetCvDiffTime(void)
|
|
{
|
|
return (CV_Diff_ProtectTime / 1000);
|
|
}
|
|
|
|
u32 GetTpDiffTime()
|
|
{
|
|
return (Temp_Diff_ProtectTime / 1000);
|
|
}
|
|
|
|
void ProcessSafety_CellVoltageDiff(void)
|
|
{
|
|
device_status.warning.bit.cell_voltage_diff = 0;
|
|
|
|
if (device_value.BatVoltage >= CELL_DEVIATION_CHECK_VOLTAGE)
|
|
{
|
|
/* Cell Voltage Diff protection (Cutoff charge if diff >= 200mV holds for 24h, latch until MCU reset) */
|
|
if (device_status.protection.bit.cell_voltage_diff)
|
|
{
|
|
// KT Requirement: Once tripped, latch protection and do not auto-recover until MCU reset
|
|
}
|
|
else
|
|
{
|
|
// Alarm check: Cutoff charge if cell diff >= 200mV holds for CV_Diff_ProtectHoldTime (default 24h)
|
|
if (device_value.Cell.avg.diff >= device_param.safety.cv_diff.Cell_Voltage_Diff_Threshold)
|
|
{
|
|
if (CV_Diff_ProtectTime == 0)
|
|
{
|
|
device_status.protection.bit.cell_voltage_diff = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CV_Diff_ProtectTime = CV_Diff_ProtectHoldTime;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (device_status.protection.bit.cell_voltage_diff == false)
|
|
{
|
|
CV_Diff_ProtectTime = CV_Diff_ProtectHoldTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Set_CV_Diff_ProtectHoldTime(u32 hold_time_ms)
|
|
{
|
|
if (hold_time_ms == 0)
|
|
{
|
|
CV_Diff_ProtectHoldTime = CV_DIFF_PROTECT_HOLD_TIME;
|
|
}
|
|
else
|
|
{
|
|
CV_Diff_ProtectHoldTime = hold_time_ms;
|
|
}
|
|
|
|
if (device_status.protection.bit.cell_voltage_diff == false)
|
|
{
|
|
CV_Diff_ProtectTime = CV_Diff_ProtectHoldTime;
|
|
}
|
|
}
|
|
|
|
void dec_temp_diff_time(u32 tick)
|
|
{
|
|
if (Temp_Diff_ProtectTime > tick)
|
|
Temp_Diff_ProtectTime -= tick;
|
|
else
|
|
Temp_Diff_ProtectTime = 0;
|
|
}
|
|
|
|
void ProcessSafety_TempDiff(void)
|
|
{
|
|
/* Temp Diff protection (24h continuous >= 3.0C diff cut off charging) */
|
|
if (device_status.protection.bit.temp_diff)
|
|
{
|
|
// Latch protection until reset
|
|
}
|
|
else
|
|
{
|
|
if ((device_status.error.bit.temp_sensor == false) && (device_value.Temp.avg.diff >= Temp_Diff_Threshold))
|
|
{
|
|
if (Temp_Diff_ProtectTime == 0)
|
|
{
|
|
device_status.protection.bit.temp_diff = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Temp_Diff_ProtectTime = Temp_Diff_ProtectHoldTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Set_Temp_Diff_ProtectHoldTime(u32 hold_time_ms)
|
|
{
|
|
if (hold_time_ms == 0)
|
|
{
|
|
Temp_Diff_ProtectHoldTime = TEMP_DIFF_PROTECT_HOLD_TIME;
|
|
}
|
|
else
|
|
{
|
|
Temp_Diff_ProtectHoldTime = hold_time_ms;
|
|
}
|
|
|
|
if (device_status.protection.bit.temp_diff == false)
|
|
{
|
|
Temp_Diff_ProtectTime = Temp_Diff_ProtectHoldTime;
|
|
}
|
|
}
|
|
|
|
void Set_Temp_Diff_Threshold(u16 th)
|
|
{
|
|
if (th == 0)
|
|
Temp_Diff_Threshold = TEMP_DIFF_PROTECT_THRESHOLD;
|
|
else
|
|
Temp_Diff_Threshold = th;
|
|
}
|
|
|
|
u16 Get_Temp_Diff_Threshold(void)
|
|
{
|
|
return Temp_Diff_Threshold;
|
|
}
|
|
|
|
#define OP_STS_STANDBY 0x0000
|
|
#define OP_STS_CHARGING 0x0001
|
|
#define OP_STS_DISCHARGING 0x0002
|
|
#define OP_STS_WARMINUP 0x0003
|
|
|
|
void Process_FetControl(void)
|
|
{
|
|
if ((device_status.protection.bit.afe_fail) || (device_status.error.bit.temp_sensor))
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
return;
|
|
}
|
|
|
|
// Charge Protection Check
|
|
if (device_status.protection.bit.cell_over_voltage) // Cell Over Voltage
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else if (device_status.protection.bit.over_voltage) // System Over Voltage
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else if (device_status.protection.bit.chg_over_current) // Charge Over Current
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else if (device_status.protection.bit.chg_high_temp) // Charge High Temperature
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else if (device_status.protection.bit.chg_low_temp) // Charge Low Temperature
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
//u32 OCC_CRITICAL_Tick = 60 * 1000;
|
|
//u8 OCC_Fail_Count = 0;
|
|
//u8 OCC_3Times_Fail = false;
|
|
else if (OCC_3Times_Fail || device_status.protection.bit.critial_over_current)
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
// device_status.battery_status.bit.DSG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else if (device_status.protection.bit.cell_voltage_diff || device_status.protection.bit.temp_diff) // Cell Voltage Diff & Temp Diff Protection (Cutoff charge if held 24h)
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
else
|
|
{
|
|
device_status.battery_status.bit.CHG_C = true;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
|
|
// Discharge Protection Check
|
|
if (device_status.protection.bit.cell_under_voltage) // Cell Under Voltage
|
|
{
|
|
// device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
}
|
|
else if (device_status.protection.bit.under_voltage) // System Under Voltage
|
|
{
|
|
// device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
}
|
|
else if (device_status.protection.bit.dsg_over_current) // Discharge Over Current
|
|
{
|
|
// device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
}
|
|
else if (device_status.protection.bit.dsg_high_temp) // Discharge High Temperature
|
|
{
|
|
// device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
}
|
|
else if (device_status.protection.bit.dsg_low_temp) // Discharge Low Temperature
|
|
{
|
|
// device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.DSG_C = false;
|
|
}
|
|
else // No Protection
|
|
{
|
|
device_status.battery_status.bit.DSG_C = true;
|
|
}
|
|
|
|
if (device_status.protection.bit.cell_voltage_diff || device_status.protection.bit.temp_diff)
|
|
{
|
|
device_status.battery_status.bit.CHG_C = false;
|
|
device_status.battery_status.bit.ZVC_C = false;
|
|
}
|
|
}
|
|
|
|
void ProcessStatusCheck(void)
|
|
{
|
|
// Alarm Status
|
|
if (device_status.battery_status.bit.INIT == false)
|
|
device_status.alarm_status = 0x0003; // Warming Up
|
|
else if (device_status.protection.value != 0)
|
|
device_status.alarm_status = 0x0002; // Protection
|
|
else if (device_status.warning.value != 0)
|
|
device_status.alarm_status = 0x0001; // Warning
|
|
else
|
|
device_status.alarm_status = 0x0000; // Normal
|
|
|
|
// Operating Status
|
|
if (device_status.battery_status.bit.INIT == false)
|
|
{
|
|
device_status.op_status = 0x0004; // Warming Up
|
|
}
|
|
else
|
|
{
|
|
if (device_status.battery_status.bit.RXM == false)
|
|
{
|
|
switch (device_status.op_status)
|
|
{
|
|
case OP_STS_STANDBY: // Standby
|
|
case 0x0003: // Floating
|
|
if (device_value.CCurrent > (device_param.chg_ctrl.current_thr.Charge_Detection_Threshold / 100))
|
|
{
|
|
device_status.op_status = 0x0001;
|
|
}
|
|
else if (device_value.DCurrent > (device_param.chg_ctrl.current_thr.Discharge_Detection_Threshold / 100))
|
|
{
|
|
device_status.op_status = 0x0002;
|
|
}
|
|
break;
|
|
case 0x0001: // Charging
|
|
if (device_value.DCurrent > (device_param.chg_ctrl.current_thr.Discharge_Detection_Threshold / 100))
|
|
{
|
|
device_status.op_status = 0x0002;
|
|
}
|
|
else if ((device_value.CCurrent < ((device_param.chg_ctrl.current_thr.Charge_Detection_Threshold - 1000) / 100)) ||
|
|
(device_status.battery_status.bit.CHG_C == false))
|
|
{
|
|
device_status.op_status = OP_STS_STANDBY;
|
|
}
|
|
break;
|
|
case 0x0002: // Discharging
|
|
if (device_value.CCurrent > (device_param.chg_ctrl.current_thr.Charge_Detection_Threshold / 100))
|
|
{
|
|
device_status.op_status = 0x0001;
|
|
}
|
|
else if (device_value.DCurrent < ((device_param.chg_ctrl.current_thr.Discharge_Detection_Threshold - 1000) / 100))
|
|
{
|
|
device_status.op_status = OP_STS_STANDBY; // Standby
|
|
}
|
|
break;
|
|
case 0x0004: // Warming Up
|
|
device_status.op_status = 0x0000; // Standby
|
|
break;
|
|
default:
|
|
device_status.op_status = 0x0000; // Standby
|
|
break;
|
|
}
|
|
|
|
// if (device_status.op_status == 0x0004)
|
|
// device_status.op_status = 0x0000; // Standby
|
|
// else
|
|
// {
|
|
// if (device_value.CCurrent > (device_param.chg_ctrl.current_thr.Charge_Detection_Threshold / 100))
|
|
// {
|
|
// device_status.op_status = 0x0001;
|
|
// }
|
|
// else if (device_value.DCurrent > (device_param.chg_ctrl.current_thr.Discharge_Detection_Threshold / 100))
|
|
// {
|
|
// device_status.op_status = 0x0002;
|
|
// }
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
switch (device_status.op_status)
|
|
{
|
|
case 0x0000: // Stand by
|
|
// if (device_value.BatVoltage >= (device_param.chg_ctrl.chg_cfg.ST_Chg_Voltage))
|
|
if (device_value.BatVoltage >= 5200)
|
|
{
|
|
if (device_status.protection.value == 0)
|
|
device_status.op_status = 0x0003; // Floating
|
|
}
|
|
break;
|
|
case 0x0003: // Float Charge
|
|
// if (device_value.BatVoltage <= (device_param.chg_ctrl.chg_cfg.ST_Chg_Voltage - (device_param.chg_ctrl.term_cfg.Taper_Voltage / 10)))
|
|
if (device_value.BatVoltage <= 5180)
|
|
{
|
|
device_status.op_status = 0x0000; // Floating
|
|
}
|
|
break;
|
|
default:
|
|
// if ((device_value.BatVoltage >= (device_param.chg_ctrl.chg_cfg.ST_Chg_Voltage))
|
|
if ((device_value.BatVoltage >= 5200)
|
|
&& (device_status.protection.value == 0))
|
|
device_status.op_status = 0x0003; // Floating
|
|
else
|
|
device_status.op_status = 0x0000; // Standby
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (device_status.op_status == OP_STS_DISCHARGING)
|
|
{
|
|
device_status.battery_status.bit.CHG_C = true;
|
|
}
|
|
}
|
|
}
|
|
|