forked from gary/BCU
2
0
Fork 0
BCU/app/stm32fxxx_app/app/bmu_adbms1818.c

461 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @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);
}