461 lines
13 KiB
C
461 lines
13 KiB
C
/******************************************************************************
|
||
* @file bmu_adbms1818.h
|
||
* @brief LT6820-ADBMS1818菊花链采集
|
||
* @version V1.0
|
||
* @author Gary 2024-11-13
|
||
* @copyright
|
||
******************************************************************************/
|
||
#include "bmu_adbms1818.h"
|
||
|
||
BmuItem bmu_data;
|
||
|
||
static uint8_t adapt_falg = 0;
|
||
//adapt ic number
|
||
void bmu_adapt_ic_num(void)
|
||
{
|
||
uint8_t i = 0;
|
||
for(i = 0;i < 10;i++)
|
||
{
|
||
run_command(1,BMU_MAX_NUM*BMU_MAX_IC_NUM);
|
||
}
|
||
|
||
for(i = 0;i < BMU_MAX_NUM*BMU_MAX_IC_NUM;i++)
|
||
{
|
||
if(bmu_data.ic[i].config.rx_pec_match == 1)
|
||
{
|
||
bmu_data.total_ic_adapt_num = i + 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
bmu_data.total_ic_num = bmu_data.total_ic_adapt_num;
|
||
}
|
||
|
||
|
||
//
|
||
void bmu_adapt_volt_temp(void)
|
||
{
|
||
uint16_t icIdx = 0,_cellIdx = 0,_ntcIdx = 0,i = 0;
|
||
if(bmu_data.cellntc_nomatch == 1 || adapt_falg == 1)
|
||
{
|
||
for(icIdx = 0;icIdx < BMU_MAX_IC_NUM * BMU_MAX_NUM;icIdx++)
|
||
{
|
||
for(i = 0;i < IC_MAX_CELL_NUM;i++)
|
||
{
|
||
if(bmu_data.ic[icIdx].cells.c_codes[i] / 10 < IC_CROSS_CELL_VOLT)
|
||
{
|
||
//This condition indicates a crossover point
|
||
}
|
||
else
|
||
{
|
||
bmu_data.cell_actual_pos[_cellIdx] = i;
|
||
bmu_data.cell_actual_ic[_cellIdx] = icIdx;
|
||
_cellIdx++;
|
||
}
|
||
}
|
||
}
|
||
|
||
bmu_data.total_cell_num = _cellIdx;
|
||
|
||
//calc temp data
|
||
for(icIdx = 0;icIdx < BMU_MAX_IC_NUM * BMU_MAX_NUM;icIdx++)
|
||
{
|
||
for(i = 0;i < IC_MAX_NTC_NUM;i++)
|
||
{
|
||
if(bmu_data.ic[icIdx].aux.a_codes[i] / 10 > IC_CROSS_TEMP_FLOAT)
|
||
{
|
||
//This condition indicates a crossover point
|
||
}
|
||
else
|
||
{
|
||
bmu_data.ntc_actual_pos[_ntcIdx] = i;
|
||
bmu_data.ntc_actual_ic[_ntcIdx] = icIdx;
|
||
_ntcIdx++;
|
||
}
|
||
}
|
||
}
|
||
|
||
bmu_data.total_temp_num = _ntcIdx;
|
||
}
|
||
|
||
//bmu_ic_num is must be config right
|
||
bmu_data.bmu_ic_num = get_eeprom_data(kEep_AfeNum_CellNum, kEepromDataType_High);
|
||
|
||
bmu_data.bmu_cell_num = bmu_data.total_cell_num / bmu_data.bmu_ic_num;
|
||
bmu_data.bmu_temp_num = bmu_data.total_temp_num / bmu_data.bmu_ic_num;
|
||
|
||
}
|
||
|
||
void bmu_init_isoSpi(void)
|
||
{
|
||
drv_spi_init(kSpiDev_1, kSpiFreq_Div256, kSpiMode_C1E1, SpiFrame_MSBFirst, kGpioType_SPI1_Clk, kGpioType_SPI1_Miso, kGpioType_SPI1_Mosi);
|
||
ADBMS1818_init(bmu_data.bmu_num * bmu_data.bmu_ic_num, bmu_data.ic);
|
||
}
|
||
|
||
|
||
|
||
//初始化bmu
|
||
void bmu_config_init(void)
|
||
{
|
||
uint8_t idx = 0;//,NtcNum = 0;
|
||
uint16_t cell_num =0, temp_num = 0;
|
||
|
||
drv_gpio_set_pin_status(kGpioType_SP1_Cs_En2, kGpioStatus_Low);
|
||
//drv_gpio_set_pin_status(kGpioType_SP1_Cs_En1, kGpioStatus_Low);
|
||
bmu_data.bmu_num = get_eeprom_data(kEep_DevAddr_SlaverNum, kEepromDataType_Low);
|
||
//bmu_data.bmu_num = 1;
|
||
if (bmu_data.bmu_num > BMU_MAX_NUM || bmu_data.bmu_num == 0)
|
||
{
|
||
bmu_data.bmu_num = BMU_MAX_NUM;
|
||
}
|
||
//NtcNum = get_eeprom_data(kEep_reserver_NtcNum, kEepromDataType_Low);
|
||
bmu_data.bmu_ic_num = get_eeprom_data(kEep_AfeNum_CellNum, kEepromDataType_High);
|
||
bmu_data.total_ic_num = bmu_data.bmu_num * bmu_data.bmu_ic_num;
|
||
bmu_data.ic = bsp_adbms1818_global();
|
||
bmu_data.total_cell_num = get_eeprom_data(kEep_CellNum, kEepromDataType_Full);
|
||
bmu_data.total_temp_num = get_eeprom_data(kEep_TempNum, kEepromDataType_Full);
|
||
|
||
//bmu_data.total_cell_num = 16;
|
||
//bmu_data.total_temp_num = 8;
|
||
|
||
//set num from hmi =>adapt num for furture
|
||
cell_num = bmu_data.total_cell_num / bmu_data.bmu_num;
|
||
temp_num = bmu_data.total_temp_num / bmu_data.bmu_num;
|
||
|
||
bmu_data.bmu_cell_num = cell_num;
|
||
bmu_data.bmu_temp_num = temp_num;
|
||
|
||
uint8_t i = 0;
|
||
cell_num =0, temp_num = 0;
|
||
|
||
//统计ic中的电压和ntc对应的真实序号
|
||
uint32_t cell_actual_pos[IC_MAX_CELL_NUM] = {0},ntc_actual_pos[IC_MAX_CELL_NUM] = {0},low_value = 0,high_value = 0,order = 0;
|
||
for(idx = 0;idx < bmu_data.bmu_ic_num;idx++)
|
||
{
|
||
low_value = get_eeprom_data(kEep_FirstIAfe_CellPos + idx * 2, kEepromDataType_Full);
|
||
high_value = get_eeprom_data(kEep_FirstIAfe_CellPos + idx * 2 + 1, kEepromDataType_Full);
|
||
cell_actual_pos[idx] = low_value + (high_value << 16);
|
||
|
||
for(i = 0; i < IC_MAX_CELL_NUM;i++)
|
||
{
|
||
if(KIT_GET_BIT_VAL(cell_actual_pos[idx],i) == 1)
|
||
{
|
||
bmu_data.cell_actual_pos[order] = i;
|
||
bmu_data.cell_actual_ic[order] = idx;
|
||
order++;
|
||
}
|
||
}
|
||
//cell num of crossover configuration >= The configured number of cell
|
||
//then Based on the configured number of voltages.
|
||
if(order > bmu_data.bmu_cell_num)
|
||
{
|
||
bmu_data.cellntc_nomatch = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
order = 0; //@wkun 刚才发现order没有给默认值0,受到上面处理影响
|
||
|
||
//统计ic中的电压和ntc对应的真实序号
|
||
for(idx = 0;idx < bmu_data.bmu_ic_num;idx++)
|
||
{
|
||
//@wkun 此处注意是需要上位机下发配置,告诉bms哪个位置接了温感,刚才发现次数全是ff所以不影响结果,最好上位机需要设置下,
|
||
low_value = get_eeprom_data(kEep_FirstIAfe_NtcPos + idx * 2, kEepromDataType_Full);
|
||
high_value = get_eeprom_data(kEep_FirstIAfe_NtcPos + idx * 2 + 1, kEepromDataType_Full);
|
||
ntc_actual_pos[idx] = low_value + (high_value << 16);
|
||
|
||
for(i = 0; i < IC_MAX_NTC_NUM;i++)
|
||
{
|
||
if(KIT_GET_BIT_VAL(ntc_actual_pos[idx],i) == 1)
|
||
{
|
||
bmu_data.ntc_actual_pos[order] = i;
|
||
bmu_data.ntc_actual_ic[order] = idx;
|
||
order++;
|
||
}
|
||
}
|
||
//ntc num of crossover configuration >= The configured number of ntc
|
||
//then Based on the configured number of ntc.
|
||
if(order > bmu_data.bmu_temp_num)
|
||
{
|
||
bmu_data.cellntc_nomatch = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void bmu_unit_data_handler()
|
||
{
|
||
uint8_t i = 0;
|
||
uint16_t cell_pos = 0, temp_pos = 0;
|
||
for (i = 0; i < bmu_data.bmu_num; i++)
|
||
{
|
||
BmuUnit* pBmu = NULL;
|
||
pBmu = &bmu_data.bmu_unit[i];
|
||
pBmu->ic_num = get_eeprom_data(kEep_AfeNum_CellNum, kEepromDataType_High);
|
||
|
||
pBmu->data[kBmuData_CellNum] = bmu_data.bmu_cell_num;
|
||
pBmu->data[kBmuData_TempNum] = bmu_data.bmu_temp_num;
|
||
|
||
pBmu->cell_volt_buf = &bmu_data.cell_volt_total_buf[cell_pos];
|
||
pBmu->cell_temp_buf = &bmu_data.cell_temp_total_buf[temp_pos];
|
||
|
||
cell_pos += bmu_data.bmu_cell_num;
|
||
temp_pos += bmu_data.bmu_temp_num;
|
||
}
|
||
|
||
bmu_data.pole_temp_buf = &bmu_data.cell_temp_total_buf[temp_pos];
|
||
}
|
||
|
||
|
||
void bmu_comm_offline_check(uint32_t base_time)
|
||
{
|
||
uint8_t i = 0;uint16_t timeout = 0;
|
||
for (i = 0; i < bmu_data.bmu_num; i++)
|
||
{
|
||
uint8_t *buf = bmu_data.ic[i].cells.pec_match;
|
||
if(kit_check_sum8(buf, 6) == 0)
|
||
{
|
||
bmu_data.bmu_unit[i].comm_fault = 1;
|
||
bmu_data.bmu_unit[i].timeout += base_time;
|
||
KIT_SET_BIT_MASK_32(bmu_data.bmu_unit[i].data[kBmuData_Status], kBmuStatus_Online);
|
||
}
|
||
else
|
||
{
|
||
bmu_data.bmu_unit[i].comm_fault = 1;
|
||
bmu_data.bmu_unit[i].timeout += base_time;
|
||
|
||
timeout = get_eeprom_data(kEep_MSCommAlarm1Dly,kEepromDataType_Full);
|
||
if(bmu_data.bmu_unit[i].timeout > timeout)
|
||
{
|
||
KIT_CLR_BIT_32(bmu_data.bmu_unit[i].data[kBmuData_Status], kBmuStatus_Online);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void bmu_vlot_breakline_check()
|
||
{
|
||
|
||
|
||
}
|
||
|
||
static int tempJudge_cnt[26][9] = {0};
|
||
//static int tempCellErr_cnt = 0;
|
||
//@wkun the here can add temp line break or connect
|
||
void bmu_temp_breakline_check(int value, int bmuIdx, int tempIdx)
|
||
{
|
||
//核心逻辑是通过每个bmu中的温度是否大于60000来确定温感排线是否有问题,通过for循环,然后将故障塞入kFaultCode_TempCable对应的故障中
|
||
//bms_get_bmu_fault_bit(kBmuFaultBit_TempCable),将这个接口中的数据,如果有则置1,否则为0
|
||
if (value > 6000)
|
||
{
|
||
tempJudge_cnt[bmuIdx][tempIdx]++;
|
||
}
|
||
if(tempJudge_cnt[bmuIdx][tempIdx] > 1)
|
||
{
|
||
bms_set_bmu_fault_bit(kBmuFaultBit_TempCable, 1);
|
||
}
|
||
}
|
||
|
||
|
||
bool bmu_is_cell_volt_valid(uint16_t value)
|
||
{
|
||
bool res = false;
|
||
if ((value >= 1000) || (value <= 4000))
|
||
{
|
||
res = true;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
static void bmu_statistic_cell_volt(uint16_t bmuIdx)
|
||
{
|
||
uint32_t i, sum_value = 0, valid_num = 0;
|
||
uint16_t value, max_value = 0, min_value = 0xFFFF, max_idx = 0, min_idx = 0;
|
||
for (i = 0; i < bmu_data.bmu_cell_num; i++) //最高、最低温度
|
||
{
|
||
value = bmu_data.bmu_unit[bmuIdx].cell_volt_buf[i];
|
||
|
||
//实时计算防止个别电芯真放空为0,或者充满
|
||
if(value > 1000 && value < 4000)
|
||
{
|
||
sum_value += value;
|
||
valid_num++;
|
||
}
|
||
if(max_value < value)
|
||
{
|
||
max_idx = i;
|
||
max_value = value;
|
||
}
|
||
|
||
if(min_value > value)
|
||
{
|
||
min_idx = i;
|
||
min_value = value;
|
||
}
|
||
}
|
||
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_TotalVolt] = sum_value;
|
||
|
||
if(valid_num > 0)
|
||
{
|
||
sum_value /= valid_num;
|
||
}
|
||
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_AvgVolt] = sum_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MaxVolt] = max_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MaxVoltIdx] = max_idx;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MinVolt] = min_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MinVoltIdx] = min_idx;
|
||
}
|
||
|
||
bool bmu_is_cell_temp_valid(uint16_t value)
|
||
{
|
||
bool res = false;
|
||
//if ((value >= 60000) || (value <= KIT_NTC_TEMP_OPEN_VALUE))
|
||
if ((value <= 60000)) //大于60000,不参与故障统计
|
||
{
|
||
res = true;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
|
||
static void bmu_statistic_cell_temp(uint16_t bmuIdx)
|
||
{
|
||
uint32_t i, sum_value = 0, valid_num = 0;
|
||
uint16_t value, max_value = 0, min_value = 0xFFFF, max_idx = 0, min_idx = 0;
|
||
|
||
for (i = 0; i < bmu_data.bmu_temp_num; i++)
|
||
{
|
||
value = bmu_data.bmu_unit[bmuIdx].cell_temp_buf[i];
|
||
if (bmu_is_cell_temp_valid(value) == false)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
sum_value += value;
|
||
valid_num++;
|
||
if(max_value < value)
|
||
{
|
||
max_idx = i;
|
||
max_value = value;
|
||
}
|
||
if(min_value > value)
|
||
{
|
||
min_idx = i;
|
||
min_value = value;
|
||
}
|
||
}
|
||
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_TotalTemp] = sum_value;
|
||
|
||
if(valid_num > 0)
|
||
{
|
||
sum_value /= valid_num;
|
||
}
|
||
|
||
//bms_set_ex_data(kExType_CellTemp, ex_st);
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_AvgTemp] = sum_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MaxTemp] = max_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MaxTempIdx] = max_idx;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MinTemp] = min_value;
|
||
bmu_data.bmu_unit[bmuIdx].statistic_data[kBmuStatistic_MinTempIdx] = min_idx;
|
||
}
|
||
|
||
|
||
//real-time calc bmu data
|
||
void bmu_data_handler(uint32_t base_time)
|
||
{
|
||
uint8_t bmuIdx = 0,cellIdx = 0,_cellIdx = 0,_bmuIdx = 0,_ntcIdx = 0;
|
||
uint16_t current = 0,load = 0, tempJudge = 0;
|
||
//calc cell volt
|
||
for(bmuIdx = 0;bmuIdx < bmu_data.total_ic_num;bmuIdx++)
|
||
{
|
||
for(cellIdx = 0;cellIdx < bmu_data.bmu_cell_num;cellIdx++)
|
||
{
|
||
_cellIdx = bmu_data.cell_actual_pos[cellIdx];
|
||
_bmuIdx = bmu_data.cell_actual_ic[cellIdx];
|
||
bmu_data.bmu_unit[bmuIdx].cell_volt_buf[cellIdx] = bmu_data.ic[bmuIdx].cells.c_codes[_cellIdx] / 10;
|
||
}
|
||
//统计电压
|
||
bmu_statistic_cell_volt(bmuIdx);
|
||
}
|
||
|
||
//calc temp data
|
||
for(bmuIdx = 0;bmuIdx < bmu_data.total_ic_num;bmuIdx++)
|
||
{
|
||
for(cellIdx = 0;cellIdx < bmu_data.bmu_temp_num;cellIdx++)
|
||
{
|
||
_ntcIdx = bmu_data.ntc_actual_pos[cellIdx]; //@wkun 此处还是全0,不对,继续排查
|
||
_bmuIdx = bmu_data.ntc_actual_ic[cellIdx];
|
||
current = KIT_MAX((3000 - (bmu_data.ic[bmuIdx].aux.a_codes[_ntcIdx] / 10)),0) / 10; //ma
|
||
if(KIT_ABS_DIFF(current,0) < 0.0001)
|
||
{
|
||
current = 1;
|
||
}
|
||
load = (bmu_data.ic[bmuIdx].aux.a_codes[_ntcIdx] / 10) * 1000 / current; //修订索引错误
|
||
tempJudge = (bms_get_linear_temp(load, kNtcType_CWFH708_H713) - 500) / 10;
|
||
bmu_data.bmu_unit[bmuIdx].cell_temp_buf[cellIdx] = tempJudge;
|
||
bmu_temp_breakline_check(tempJudge, bmuIdx, _ntcIdx);
|
||
}
|
||
//统计温度
|
||
bmu_statistic_cell_temp(bmuIdx);
|
||
}
|
||
//alarm monitor
|
||
//bmu_comm_offline_check(base_time);
|
||
bmu_vlot_breakline_check();
|
||
|
||
}
|
||
|
||
|
||
|
||
void bms_bmu_init()
|
||
{
|
||
bmu_config_init();
|
||
bmu_init_isoSpi();
|
||
bmu_unit_data_handler();
|
||
|
||
//Automatic Recognition
|
||
if(adapt_falg == 1)
|
||
{
|
||
bmu_adapt_ic_num();
|
||
bmu_adapt_volt_temp();
|
||
bmu_unit_data_handler();
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
void bms_poll_bmu(uint32_t base_time)
|
||
{
|
||
//Automatic Recognition
|
||
if(adapt_falg == 1)
|
||
{
|
||
bmu_adapt_ic_num();
|
||
bmu_adapt_volt_temp();
|
||
bmu_unit_data_handler();
|
||
}
|
||
run_command(3,bmu_data.bmu_num*bmu_data.bmu_ic_num);
|
||
run_command(4,bmu_data.bmu_num*bmu_data.bmu_ic_num);
|
||
bmu_data_handler(base_time);
|
||
|
||
run_command(5,bmu_data.bmu_num*bmu_data.bmu_ic_num);
|
||
run_command(6,bmu_data.bmu_num*bmu_data.bmu_ic_num);
|
||
bmu_data_handler(base_time);
|
||
|
||
//温感检测是否脱落,加上了防抖,需要两次大于6000,才设置温感排线错误,温感排线错误显示的有点慢
|
||
//温感的值最开始全是大于6000的,第二次才是采集值
|
||
memset(tempJudge_cnt, 0, sizeof(tempJudge_cnt));
|
||
//2-5 @wangk add this line bcu statistic data is show
|
||
bms_poll_statistic(0);
|
||
//2-6 @wangk
|
||
bms_poll_run_status(base_time);
|
||
//2-10 @wangk
|
||
task_dido_ctrl_handle(1000);
|
||
}
|
||
|
||
|
||
|