重构充电协议模块,统一源载参数管理与流程
1. apps/chrg/applications/utils/chrg_def.h: 移除vc_pd_t结构体中mm数组下标,改为单实例 2. apps/chrg/applications/utils/chrg_north_pkg.c: 修正CRC校验调用,调整pd_get参数访问方式 3. apps/chrg/applications/utils/chrg_source.h: 重构src_vc_t和chrg_src_t结构体,移除冗余字段,新增set_volt/set_curr和pd_set单实例 4. apps/chrg/applications/thread/chrg_roll_nor.c: 修正CC选择变量名,新增PD数据获取流程 5. apps/chrg/applications/thread/chrg_lcd.c: 重构LCD解析逻辑,区分源载电压处理,新增工作状态触发 6. apps/chrg/applications/thread/chrg_north.c: 新增协议电压规则修正函数,重构源参数控制逻辑 7. apps/chrg/applications/thread/chrg_comm.c: 新增pd_changed参数差异标志,重构源参数读写与差异比较逻辑 8. apps/chrg/applications/utils/chrg_source.c: 重构源工作状态机,新增电压补偿逻辑,重构PD协议填充函数 9. docs\2026-07-29-self-loop-aging-test-plan.md: 新增四通道自举老化测试计划文档
This commit is contained in:
@@ -57,7 +57,7 @@ static rt_uint8_t g_shadow_dirty[TOTAL_NOR_CHS] = {0}; /* 0=已生效 1=待生
|
||||
|
||||
/*
|
||||
* Source和Sink共用的参数差异结果。前五项是两个角色都具备的控制属性,
|
||||
* 后三项只用于Sink快充协议配置;Source比较时保持为RT_FALSE。
|
||||
* pd_changed用于Source完整协议参数比较,后三项用于Sink快充协议配置。
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
@@ -66,6 +66,7 @@ typedef struct
|
||||
rt_bool_t cv_changed;
|
||||
rt_bool_t voltage_changed;
|
||||
rt_bool_t current_changed;
|
||||
rt_bool_t pd_changed;
|
||||
rt_bool_t group_changed;
|
||||
rt_bool_t pro_voltage_changed;
|
||||
rt_bool_t pro_current_changed;
|
||||
@@ -872,22 +873,24 @@ static rt_uint16_t src_proto_lookup(rt_uint16_t reg_val)
|
||||
*****************************************************************/
|
||||
static rt_uint16_t src_type_lookup(rt_uint16_t reg_val,struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct vc_pd_t *pPD = &pSW->source.pd_set;
|
||||
|
||||
switch(reg_val){
|
||||
case 0:
|
||||
pSW->source.src = 0;
|
||||
pSW->source.pps = 0;
|
||||
pPD->src_type = TYPE_SRC_PDO;
|
||||
pPD->pps_type = TYPE_PPS_SPRPPS;
|
||||
break;
|
||||
case 1:
|
||||
pSW->source.src = 0;
|
||||
pSW->source.pps = 1;
|
||||
pPD->src_type = TYPE_SRC_PDO;
|
||||
pPD->pps_type = TYPE_PPS_EPR;
|
||||
break;
|
||||
case 2:
|
||||
pSW->source.src = 3;
|
||||
pSW->source.pps = 0;
|
||||
pPD->src_type = TYPE_SRC_APDO;
|
||||
pPD->pps_type = TYPE_PPS_SPRPPS;
|
||||
break;
|
||||
case 3:
|
||||
pSW->source.src = 3;
|
||||
pSW->source.pps = 1;
|
||||
pPD->src_type = TYPE_SRC_APDO;
|
||||
pPD->pps_type = TYPE_PPS_EPR;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
@@ -1127,13 +1130,13 @@ eMBException funcWriteMultipleHoldingRegister (rt_uint8_t *reqFrame, rt_uint16_t
|
||||
switch (sout_reg)
|
||||
{
|
||||
case REG_VOLTAGE_OUT + 1:
|
||||
pSW->source.vc.set_voltage = sou_value;
|
||||
pSW->source.set_volt = sou_value;
|
||||
pSW->sink.loadv = sou_value;
|
||||
chrg_set_sou_reg(ch, sout_reg, sou_value);
|
||||
rt_kprintf("voltage=%d", sou_value);
|
||||
break;
|
||||
case REG_CURRENT_OUT + 1:
|
||||
pSW->source.vc.set_current = sou_value;
|
||||
pSW->source.set_curr = sou_value;
|
||||
pSW->sink.loadc = sou_value;
|
||||
chrg_set_sou_reg(ch, sout_reg, sou_value);
|
||||
break;
|
||||
@@ -2223,21 +2226,21 @@ static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
// rt_kprintf("[SRC CH%d] Mode=%d\n", ch + 1, sou_value);
|
||||
break;
|
||||
case SRC_REG_MIN_VOLT: // 0x03: 最小电压 (mV)
|
||||
pSW->source.min_vol = sou_value;
|
||||
pSW->source.pd_set.mm.min_vol = sou_value;
|
||||
//rt_kprintf("[SRC CH%d] MinVolt=%d mV\n", ch + 1, sou_value);
|
||||
break;
|
||||
case SRC_REG_MAX_VOLT: // 0x04: 最大电压 (mV)
|
||||
pSW->source.vc.set_voltage = sou_value;
|
||||
pSW->source.pd_set.mm.max_vol = sou_value;
|
||||
// rt_kprintf("[SRC CH%d] MaxVolt=%d mV\n", ch + 1, sou_value);
|
||||
break;
|
||||
|
||||
case SRC_REG_MAX_CURR: // 0x05: 最大电流 (mA)
|
||||
pSW->source.vc.set_current = sou_value;
|
||||
pSW->source.pd_set.mm.max_cur = sou_value;
|
||||
//rt_kprintf("[SRC CH%d] MaxCurr=%d mA\n", ch + 1, sou_value);
|
||||
break;
|
||||
|
||||
case SRC_REG_CC_SEL: // 0x06: CC选择
|
||||
pSW->source.cc_set = (rt_uint8_t)sou_value;
|
||||
pSW->source.CC_Set = (rt_uint8_t)sou_value;
|
||||
//rt_kprintf("[SRC CH%d] CC_SEL=%d\n", ch + 1, sou_value);
|
||||
break;
|
||||
|
||||
@@ -2258,8 +2261,8 @@ static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t
|
||||
输入参数: role:当前角色 pReal:正在运行的参数 pShadow:待生效参数
|
||||
输出参数: pDiff:各公共属性及Sink专用协议属性的变化标志
|
||||
返回说明: -
|
||||
其它说明: 本函数只计算差异,不修改状态、不发送命令;Source的电压电流
|
||||
使用vc.set_voltage/set_current,Sink使用loadv/loadc
|
||||
其它说明: 本函数只计算差异,不修改状态、不发送命令;Source直接比较
|
||||
完整pd_set,并从pd_set.mm提取标准协议电压电流差异
|
||||
*****************************************************************/
|
||||
static void chrg_comm_get_param_diff(eIDX_ID role,
|
||||
const struct chrg_switch_t *pReal,
|
||||
@@ -2276,11 +2279,16 @@ static void chrg_comm_get_param_diff(eIDX_ID role,
|
||||
pDiff->protocol_changed =
|
||||
(pReal->source.protocol != pShadow->source.protocol);
|
||||
pDiff->cc_changed =
|
||||
(pReal->source.cc_set != pShadow->source.cc_set);
|
||||
(pReal->source.CC_Set != pShadow->source.CC_Set);
|
||||
/* 两个数组均来自静态零初始化结构,填充前未定义字节保持为0。 */
|
||||
pDiff->pd_changed = (rt_memcmp(&pReal->source.pd_set,
|
||||
&pShadow->source.pd_set, sizeof(pReal->source.pd_set)) != 0);
|
||||
pDiff->voltage_changed =
|
||||
(pReal->source.vc.set_voltage != pShadow->source.vc.set_voltage);
|
||||
(pReal->source.pd_set.mm.max_vol !=
|
||||
pShadow->source.pd_set.mm.max_vol);
|
||||
pDiff->current_changed =
|
||||
(pReal->source.vc.set_current != pShadow->source.vc.set_current);
|
||||
(pReal->source.pd_set.mm.max_cur !=
|
||||
pShadow->source.pd_set.mm.max_cur);
|
||||
} else if (role == ID_SINK) {
|
||||
pDiff->protocol_changed =
|
||||
(pReal->sink.protocol != pShadow->sink.protocol);
|
||||
@@ -2373,26 +2381,50 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch,
|
||||
输入参数: ch:通道 pReal:运行参数 pShadow:待生效影子参数
|
||||
输出参数: 更新pReal、Source状态和必要的南向寄存器
|
||||
返回说明: MB_EX_NONE:成功 MB_EX_SLAVE_BUSY:命令提交失败
|
||||
其它说明: 快充协议只重置北向sub并进入WAIT;标准协议直接更新CV、电压和电流
|
||||
其它说明: 只复制Source配置字段,避免影子结构覆盖北向实时set_volt/set_curr;
|
||||
快充参数变化进入WAIT,标准协议电压统一交给RUNING状态下发
|
||||
*****************************************************************/
|
||||
static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
|
||||
struct chrg_switch_t *pReal, const struct chrg_switch_t *pShadow)
|
||||
{
|
||||
chrg_param_diff_t diff_info;
|
||||
rt_bool_t north_config_changed;
|
||||
struct vc_pd_t old_pd_set;
|
||||
eSRC_PRO old_protocol = pReal->source.protocol;
|
||||
rt_uint8_t old_cc_set = pReal->source.CC_Set;
|
||||
rt_uint8_t old_now_state = pReal->source.Now_State;
|
||||
rt_uint8_t old_work_mode = pReal->source.work_mode;
|
||||
rt_uint8_t old_cv_mode = pReal->CV_mode;
|
||||
rt_uint16_t old_voltage = pReal->source.vc.set_voltage;
|
||||
rt_uint16_t old_current = pReal->source.vc.set_current;
|
||||
rt_uint8_t old_proto_cmd = pReal->protoCmd;
|
||||
rt_uint8_t old_sub = pReal->sub;
|
||||
rt_uint16_t old_set_volt = pReal->source.set_volt;
|
||||
rt_uint16_t old_set_curr = pReal->source.set_curr;
|
||||
rt_uint16_t source_work = pShadow->source.Now_State;
|
||||
rt_uint16_t regs[3];
|
||||
rt_uint16_t vals[3];
|
||||
rt_uint16_t regs[2];
|
||||
rt_uint16_t vals[2];
|
||||
rt_uint16_t clear_reg;
|
||||
rt_uint16_t clear_val;
|
||||
rt_uint16_t target_curr;
|
||||
rt_uint8_t count = 0;
|
||||
|
||||
chrg_comm_get_param_diff(ID_SOURCE, pReal, pShadow, &diff_info);
|
||||
rt_memcpy(pReal, pShadow, sizeof(struct chrg_switch_t));
|
||||
rt_memcpy(&old_pd_set, &pReal->source.pd_set, sizeof(old_pd_set));
|
||||
north_config_changed = diff_info.protocol_changed ||
|
||||
diff_info.cc_changed || diff_info.pd_changed;
|
||||
target_curr = pShadow->source.pd_set.mm.max_cur;
|
||||
|
||||
/* 影子区只拥有COM配置;北向解析产生的运行目标和回读数据继续由pReal持有。 */
|
||||
pReal->CV_mode = pShadow->CV_mode;
|
||||
pReal->protoCmd = pShadow->protoCmd;
|
||||
pReal->source.protocol = pShadow->source.protocol;
|
||||
pReal->source.CC_Set = pShadow->source.CC_Set;
|
||||
pReal->source.Now_State = pShadow->source.Now_State;
|
||||
rt_memcpy(&pReal->source.pd_set, &pShadow->source.pd_set,
|
||||
sizeof(pReal->source.pd_set));
|
||||
|
||||
if (source_work == 0x01) {
|
||||
if (pReal->source.On_Flag == 0) {
|
||||
/* 首次启动仍需初始化功率板、继电器和WORK_START。 */
|
||||
/* 新命令要求运行时直接置位,不依赖旧工作状态。 */
|
||||
pReal->sub = IDX_SET_SOURCE_CC_SET;
|
||||
pReal->source.On_Flag = 1;
|
||||
pReal->source.work_mode = SOURCE_WORK_INIT;
|
||||
@@ -2400,40 +2432,48 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
|
||||
MB_EX_NONE : MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
|
||||
/* 协议或CC变化时,从CC设置开始重新执行北向配置链路。 */
|
||||
if (diff_info.protocol_changed || diff_info.cc_changed) {
|
||||
/* 协议、CC或任一pd_set字段变化时,重新执行北向配置链路。 */
|
||||
if (north_config_changed) {
|
||||
pReal->sub = IDX_SET_SOURCE_CC_SET;
|
||||
}
|
||||
|
||||
pReal->source.work_mode = SOURCE_WORK_WAIT;
|
||||
if (diff_info.protocol_changed || diff_info.cc_changed) {
|
||||
/* 协议或CC切换前先清零南向输出,帮助功率板退出旧协议状态,
|
||||
* 后续北向轮询再按CC、协议、VC顺序完成新协议握手。 */
|
||||
clear_reg = REG_VOLTAGE_OUT + 1;
|
||||
clear_val = 0;
|
||||
if (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch,
|
||||
&clear_reg, &clear_val, 1) != 0) {
|
||||
goto source_effect_submit_failed;
|
||||
}
|
||||
pReal->source.set_volt = 0;
|
||||
}
|
||||
|
||||
if (pReal->source.protocol != PRO_NONE) {
|
||||
/* 快充目标值由北向协商回码决定,COM生效阶段不直接写功率板。 */
|
||||
/* 快充只更新协议配置并等待协商回码,不直接改功率板输出。 */
|
||||
return MB_EX_NONE;
|
||||
}
|
||||
|
||||
/* 从快充切到标准协议时强制同步全部直接控制参数。 */
|
||||
/* 标准协议的模式和电流可直接提交,电压只能由RUNING状态写入。 */
|
||||
if (diff_info.protocol_changed || diff_info.cv_changed) {
|
||||
regs[count] = REG_MODE;
|
||||
vals[count++] = pReal->CV_mode;
|
||||
}
|
||||
if (diff_info.protocol_changed || diff_info.voltage_changed) {
|
||||
regs[count] = REG_VOLTAGE_OUT + 1;
|
||||
vals[count++] = pReal->source.vc.set_voltage;
|
||||
}
|
||||
if (diff_info.protocol_changed || diff_info.current_changed) {
|
||||
regs[count] = REG_CURRENT_OUT + 1;
|
||||
vals[count++] = pReal->source.vc.set_current;
|
||||
vals[count++] = target_curr;
|
||||
}
|
||||
|
||||
if ((count > 0) && (chrg_sou_com_batch_submit((eIDX_SOU_CH)ch,
|
||||
regs, vals, count) != 0)) {
|
||||
pReal->CV_mode = old_cv_mode;
|
||||
pReal->source.vc.set_voltage = old_voltage;
|
||||
pReal->source.vc.set_current = old_current;
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
goto source_effect_submit_failed;
|
||||
}
|
||||
pReal->source.work_mode = SOURCE_WORK_RUNING;
|
||||
|
||||
/* COM只更新标准协议配置并保持WAIT;下一帧北向解析负责比较
|
||||
* pd_set目标与set_volt,再决定是否进入RUNING写电压。 */
|
||||
pReal->source.set_curr = target_curr;
|
||||
pReal->source.work_mode = SOURCE_WORK_WAIT;
|
||||
return MB_EX_NONE;
|
||||
}
|
||||
|
||||
@@ -2441,6 +2481,21 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
|
||||
pReal->source.work_mode = SOURCE_WORK_STOP;
|
||||
return (chrg_source_work_state(ch, pReal) == 0) ?
|
||||
MB_EX_NONE : MB_EX_SLAVE_BUSY;
|
||||
|
||||
source_effect_submit_failed:
|
||||
/* 南向命令提交失败必须恢复差异基准,保证下一次PARAM_EFFECT仍会重发。 */
|
||||
pReal->CV_mode = old_cv_mode;
|
||||
pReal->protoCmd = old_proto_cmd;
|
||||
pReal->sub = old_sub;
|
||||
pReal->source.protocol = old_protocol;
|
||||
pReal->source.CC_Set = old_cc_set;
|
||||
pReal->source.Now_State = old_now_state;
|
||||
pReal->source.work_mode = old_work_mode;
|
||||
pReal->source.set_volt = old_set_volt;
|
||||
pReal->source.set_curr = old_set_curr;
|
||||
rt_memcpy(&pReal->source.pd_set, &old_pd_set,
|
||||
sizeof(pReal->source.pd_set));
|
||||
return MB_EX_SLAVE_BUSY;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
|
||||
@@ -212,13 +212,16 @@ static int chrg_lcd_parse (rt_uint8_t *recv, rt_uint16_t len)
|
||||
Recv_Data = recv[LCD_IDX_VAL+1]<<8 | recv[LCD_IDX_VAL]; // 拼接16位电压值
|
||||
pSW = &pNOR->sw[ch];
|
||||
// 按角色存入source/sink
|
||||
pSW->source.vc.set_voltage = Recv_Data; // 电源侧电压(mV)
|
||||
pSW->source.pd_set.mm.max_vol = Recv_Data; // 电源协议目标电压(mV)
|
||||
pSW->source.set_volt = Recv_Data; // 当前准备写入功率板的电压目标
|
||||
pSW->sink.loadv = Recv_Data; // 负载侧电压(mV,)
|
||||
// 写入电压寄存器
|
||||
if(pSW->id==ID_SINK) {
|
||||
chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT+1, Recv_Data);
|
||||
/* Sink保留原直接设置方式;Source电压必须统一经过RUNING状态补偿后下发。 */
|
||||
if (pSW->id == ID_SINK) {
|
||||
chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT + 1, Recv_Data);
|
||||
} else if (pSW->source.On_Flag == 1) {
|
||||
pSW->source.work_mode = SOURCE_WORK_RUNING;
|
||||
(void)chrg_source_work_state(ch, pSW);
|
||||
}
|
||||
else chrg_set_sou_reg((eIDX_SOU_CH)ch, REG_VOLTAGE_OUT+1, 5000);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -231,7 +234,8 @@ static int chrg_lcd_parse (rt_uint8_t *recv, rt_uint16_t len)
|
||||
Recv_Data = recv[LCD_IDX_VAL+1]<<8 | recv[LCD_IDX_VAL]; // 拼接16位电流值
|
||||
pSW = &pNOR->sw[ch];
|
||||
//按角色存入source/sink
|
||||
pSW->source.vc.set_current = Recv_Data; // 电源侧电流(mA)
|
||||
pSW->source.pd_set.mm.max_cur = Recv_Data; // 电源协议最大电流(mA)
|
||||
pSW->source.set_curr = Recv_Data; // 当前准备写入功率板的电流目标
|
||||
pSW->sink.loadc = Recv_Data; // 负载侧电流(mA)
|
||||
// rt_kprintf("cur=%d",Recv_Data);
|
||||
// 写入电流寄存器
|
||||
|
||||
@@ -26,6 +26,94 @@
|
||||
|
||||
#define SOURCE_VOLT_ERROR_MV 200U
|
||||
#define SOURCE_VOLT_RETRY_FRAMES 3U
|
||||
#define SOURCE_QC_MIN_VOLT_MV 5000U
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_source_apply_protocol_voltage_rule
|
||||
函数描述: 根据电源协议类型修正北向解析得到的目标电压
|
||||
输入参数: pSW:当前通道控制结构体 volt_mv:北向解析电压(mV)
|
||||
输出参数: -
|
||||
返回说明: 应写入Source状态机的目标电压(mV)
|
||||
其它说明: QC2.0/QC3.0在完成升压协商前必须保持默认5V,因此其北向
|
||||
回码低于5000mV时统一按5000mV处理;其它协议保持原值
|
||||
*****************************************************************/
|
||||
static rt_uint16_t chrg_source_apply_protocol_voltage_rule(
|
||||
const struct chrg_switch_t *pSW, rt_uint16_t volt_mv)
|
||||
{
|
||||
if (pSW == RT_NULL) {
|
||||
return volt_mv;
|
||||
}
|
||||
|
||||
if (((pSW->source.protocol == PRO_QC20) ||
|
||||
(pSW->source.protocol == PRO_QC30)) &&
|
||||
(volt_mv < SOURCE_QC_MIN_VOLT_MV)) {
|
||||
return SOURCE_QC_MIN_VOLT_MV;
|
||||
}
|
||||
|
||||
return volt_mv;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_source_voltage_control
|
||||
函数描述: 根据目标电压与实际电压统一控制Source电压下发和重试
|
||||
输入参数: idx:当前通道 pSW:通道控制结构体 volt_mv:目标电压(mV)
|
||||
curr_ma:目标电流(mA)
|
||||
输出参数: 更新source.set_volt/set_curr、work_mode和电压重试计数
|
||||
返回说明: 0:状态处理成功 <0:参数错误或命令提交失败
|
||||
其它说明: set_volt同时作为上次目标,停止时会清零;目标变化时立即下发,
|
||||
目标不变但实际误差连续3帧超过200mV时重发
|
||||
*****************************************************************/
|
||||
static int chrg_source_voltage_control(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW, rt_uint16_t volt_mv, rt_uint16_t curr_ma)
|
||||
{
|
||||
static rt_uint8_t volt_retry_count[TOTAL_SOU_CHS] = {0};
|
||||
rt_uint16_t volt_error;
|
||||
rt_uint16_t old_volt_mv;
|
||||
rt_uint16_t old_curr_ma;
|
||||
rt_bool_t need_set = RT_FALSE;
|
||||
int ret;
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
old_volt_mv = pSW->source.set_volt;
|
||||
old_curr_ma = pSW->source.set_curr;
|
||||
pSW->source.set_volt = volt_mv;
|
||||
pSW->source.set_curr = curr_ma;
|
||||
if (!pSW->source.On_Flag) {
|
||||
return 0;
|
||||
}
|
||||
volt_error = (pSW->Now_voltage >= volt_mv) ?
|
||||
(pSW->Now_voltage - volt_mv) :
|
||||
(volt_mv - pSW->Now_voltage);
|
||||
|
||||
if (volt_mv != old_volt_mv) {
|
||||
/* 新目标与set_volt旧值不同,需要立即写入功率板。 */
|
||||
need_set = RT_TRUE;
|
||||
} else if (volt_error <= SOURCE_VOLT_ERROR_MV) {
|
||||
volt_retry_count[idx] = 0;
|
||||
} else {
|
||||
if (volt_retry_count[idx] < SOURCE_VOLT_RETRY_FRAMES) {
|
||||
volt_retry_count[idx]++;
|
||||
}
|
||||
if (volt_retry_count[idx] >= SOURCE_VOLT_RETRY_FRAMES) {
|
||||
need_set = RT_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
pSW->source.work_mode = need_set ?
|
||||
SOURCE_WORK_RUNING : SOURCE_WORK_WAIT;
|
||||
ret = chrg_source_work_state(idx, pSW);
|
||||
if ((ret == 0) && need_set) {
|
||||
volt_retry_count[idx] = 0;
|
||||
} else if ((ret != 0) && need_set) {
|
||||
/* 入队失败时恢复旧目标,使下一帧仍能立即识别为目标变化。 */
|
||||
pSW->source.set_volt = old_volt_mv;
|
||||
pSW->source.set_curr = old_curr_ma;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_source_parse
|
||||
@@ -34,8 +122,8 @@
|
||||
pNOR:北向总控结构体
|
||||
输出参数: 更新电压、电流、source.work_mode及电压重试计数
|
||||
返回说明: -
|
||||
其它说明: 标准协议只在本函数中识别,不使用北向返回值控制输出;快充协议
|
||||
读取frame_data[8~11]中的协商目标值,并统一交给RUNING状态比较
|
||||
其它说明: 标准协议使用COM配置目标参与实际电压校验;快充协议读取
|
||||
frame_data[8~11]中的协商目标值,两个分支共用误差重试逻辑
|
||||
*****************************************************************/
|
||||
void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW, struct chrg_north_t *pNOR)
|
||||
@@ -47,9 +135,12 @@ void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
return;
|
||||
}
|
||||
|
||||
/* 标准协议仍在北向解析入口处判断,但输出已经由INIT/COM直接完成。
|
||||
* 不读取北向返回电压,也不在这里重复下发南向电压。 */
|
||||
/* 标准协议不使用北向帧内目标值,但仍进入统一误差判断,确保INIT或
|
||||
* COM下发的目标电压没有生效时能够自动重试。 */
|
||||
if (pSW->source.protocol == PRO_NONE) {
|
||||
(void)chrg_source_voltage_control(idx, pSW,
|
||||
pSW->source.pd_set.mm.max_vol,
|
||||
pSW->source.pd_set.mm.max_cur);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,11 +149,9 @@ void chrg_source_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
}
|
||||
volt_mv = (frame_data[8] << 8) | frame_data[9];
|
||||
curr_ma = (frame_data[10] << 8) | frame_data[11];
|
||||
pSW->source.vc.set_voltage = volt_mv;
|
||||
pSW->source.vc.set_current = curr_ma;
|
||||
/* 北向只负责提取本次返回值;新旧电压比较放在RUNING状态完成。 */
|
||||
pSW->source.work_mode = SOURCE_WORK_RUNING;
|
||||
(void)chrg_source_work_state(idx, pSW);
|
||||
// /* 特殊协议规则只修正运行目标,不覆盖北向原始回码和COM协议配置。 */
|
||||
// volt_mv = chrg_source_apply_protocol_voltage_rule(pSW, volt_mv);
|
||||
(void)chrg_source_voltage_control(idx, pSW, volt_mv, curr_ma);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
@@ -79,10 +168,8 @@ void chrg_source_setting(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
{
|
||||
//执行输出调整
|
||||
if (pSW->source.On_Flag == 1) {
|
||||
if (pSW->source.protocol != PRO_NONE) {
|
||||
/* 标准协议不依赖北向返回值;快充协议继续解析协商结果。 */
|
||||
/* 标准协议与快充协议都由解析入口选择各自目标值并统一校验。 */
|
||||
chrg_source_parse(frame_data, idx, pSW, pNOR);
|
||||
}
|
||||
}else if(pSW->source.On_Flag == 0){
|
||||
//chrg_source_stop(frame_data,pSW,idx,&pNOR->enable[idx]);
|
||||
pSW->sub = IDX_SET_SOURCE_STOP_STATE;
|
||||
@@ -134,7 +221,7 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx,
|
||||
pSW->change_flag = 0;
|
||||
if ((rt_uint32_t)volt_mv + 2000 >= pSW->sink.pro_loadv) {
|
||||
pSW->sink.work_mode = SINK_WORK_RUNING;
|
||||
if (pSW->Now_current <= 200) {
|
||||
if (pSW->Now_current <= 200 && (pSW->sink.pro_loadc >= 200)) {
|
||||
if (++no_curr[idx] >= 3) {
|
||||
pSW->sink.work_mode = SINK_WORK_WAIT;
|
||||
no_curr[idx] = 0;
|
||||
|
||||
@@ -67,7 +67,7 @@ int sink_fill_pd_buf(rt_uint8_t group,rt_uint8_t pd_val, rt_uint16_t pd_volt, rt
|
||||
case 0xF6: // QC3.0协议
|
||||
case 0xF2: // FCP协议
|
||||
buf[0] = pd_volt / 100; // 第5字节=电压(0.1V)
|
||||
buf[1] = pd_curr / 100; // 第6字节=电流(0.1A)
|
||||
buf[1] = 0x00;//pd_curr / 100; // 第6字节=电流(0.1A)
|
||||
#if PRO_TEST_DEBUG
|
||||
rt_kprintf("type: %02X, Voltage(0.1V)=%d\n", pd_val, pd_volt/100);
|
||||
rt_kprintf("type: %02x, Curr(0.1A)=%d\n",pd_curr,pd_curr/100);
|
||||
@@ -302,7 +302,7 @@ void chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW,rt_uint8_t *enab
|
||||
chrg_roll_nor_sw_uart((eIDX_NOR_CH)ch, ID_SOURCE);
|
||||
switch(pSW->sub){
|
||||
case IDX_SET_SOURCE_CC_SET:
|
||||
source_set_cc_choose(pSW->source.cc_set);
|
||||
source_set_cc_choose(pSW->source.CC_Set);
|
||||
pSW->sub = IDX_SET_SOURCE_PD;
|
||||
break;
|
||||
case IDX_SET_SOURCE_PD:
|
||||
@@ -310,8 +310,12 @@ void chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW,rt_uint8_t *enab
|
||||
pSW->sub = IDX_GET_SOURCE_VC;
|
||||
break;
|
||||
case IDX_GET_SOURCE_VC:
|
||||
source_get_vc(pSW->source.vc.set_voltage, pSW->source.vc.set_current);
|
||||
source_get_vc(pSW->source.set_volt, pSW->source.set_curr);
|
||||
pSW->sub = IDX_GET_SOURCE_PD;
|
||||
break;
|
||||
case IDX_GET_SOURCE_PD:
|
||||
source_get_pd();
|
||||
pSW->sub = IDX_GET_SOURCE_VC;
|
||||
default:
|
||||
|
||||
break;
|
||||
|
||||
@@ -88,7 +88,7 @@ struct vc_pd_t {
|
||||
rt_uint8_t group_num; // 挡位数量
|
||||
rt_uint8_t src_type; // 源类型
|
||||
rt_uint8_t pps_type; // PPS类型
|
||||
struct vc_mm_t mm[2]; // 电压电流极值
|
||||
struct vc_mm_t mm; // 电压电流极值
|
||||
};
|
||||
|
||||
/* 邮件内容 */
|
||||
|
||||
@@ -41,7 +41,7 @@ int chrg_north_pkg_encode (eIDX_ID id, rt_uint8_t cmd, rt_uint8_t *data_in,
|
||||
if (len_in > 0) {
|
||||
rt_memcpy(&data_out[4], data_in, len_in);
|
||||
}
|
||||
data_out[len_in+4] = 0x2a;//calc_crc8(data_out, len_in+4);
|
||||
data_out[len_in+4] = calc_crc8(data_out, len_in+4);//0x2a;
|
||||
*len_out = 5+len_in;
|
||||
|
||||
return 0;
|
||||
@@ -84,9 +84,9 @@ int chrg_north_pkg_decode (rt_uint8_t *data, rt_uint16_t length, struct chrg_swi
|
||||
struct get_pd_pro_ack_t *pAck = (struct get_pd_pro_ack_t *)data;
|
||||
pS->pd_get[0].src_type = pAck->type;
|
||||
pS->pd_get[0].pps_type = pAck->pps;
|
||||
pS->pd_get[0].mm[0].max_vol = pAck->vmax;
|
||||
pS->pd_get[0].mm[0].min_vol = pAck->vmin;
|
||||
pS->pd_get[0].mm[0].max_cur = pAck->curpwr;
|
||||
pS->pd_get[0].mm.max_vol = pAck->vmax;
|
||||
pS->pd_get[0].mm.min_vol = pAck->vmin;
|
||||
pS->pd_get[0].mm.max_cur = pAck->curpwr;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -140,8 +140,10 @@ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
struct chrg_south_t *pSOU = &chrgsouth;
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
rt_uint16_t regs[5] = {REG_CURRENT_OUT + 1, REG_MODE,Eload_Start_V_ON,0, 0};
|
||||
rt_uint16_t vals[5] = {0, pSW->CV_mode,pSW->sink.volt_on, 0, 0};
|
||||
rt_uint16_t regs[5] = {REG_CURRENT_OUT + 1, REG_MODE,
|
||||
Eload_Start_V_ON, 0, 0};
|
||||
rt_uint16_t vals[5] = {0, pSW->CV_mode, pSW->sink.volt_on,
|
||||
0, 0};
|
||||
rt_uint8_t count = 3;
|
||||
|
||||
if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) {
|
||||
@@ -251,12 +253,20 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t reg = REG_WORK;
|
||||
rt_uint16_t value = WORK_STOP;
|
||||
rt_uint16_t eload_reg = REG_ELOAD;
|
||||
rt_uint16_t eload_value = ELOAD_LOAD;
|
||||
int ret;
|
||||
|
||||
ret = chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
/* 等待源模式停止命令入队后,再单独切回负载角色,避免同一批次
|
||||
* 发生源载模式切换后后续负载初始化命令被功率板忽略。 */
|
||||
ret = chrg_sou_com_batch_submit(idx, &eload_reg, &eload_value, 1);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 停止成功入队后,清除旧Source运行标志。 */
|
||||
pSW->source.On_Flag = 0;
|
||||
|
||||
@@ -17,38 +17,41 @@
|
||||
#include "chrg_roll_sou.h"
|
||||
#include "chrg_rel.h"
|
||||
|
||||
#define SOURCE_VOLT_COMPENSATION_MV 200U
|
||||
|
||||
static int chrg_source_work_running(eIDX_SOU_CH idx,
|
||||
struct chrg_switch_t *pSW);
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_source_init_submit
|
||||
函数描述: 将电源模式初始化参数批量提交到南向功率板命令队列
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: -
|
||||
返回说明: 0:提交成功 <0:参数错误或队列提交失败
|
||||
其它说明: 命令顺序为源载模式、CV/CC模式、继电器、初始电压、保护电流、启动
|
||||
其它说明: INIT不写电压;电压统一由RUNING状态写入,避免多个入口重复控制
|
||||
*****************************************************************/
|
||||
int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
/* Source启动参数一次入队,最后发送WORK_START使功率板开始输出。 */
|
||||
rt_uint16_t regs[6] = {
|
||||
rt_uint16_t regs[5] = {
|
||||
REG_ELOAD,
|
||||
REG_MODE,
|
||||
0x01,
|
||||
REG_VOLTAGE_OUT + 1,
|
||||
REG_CURRENT_OUT + 1,
|
||||
REG_WORK
|
||||
};
|
||||
rt_uint16_t vals[6] = {
|
||||
rt_uint16_t vals[5] = {
|
||||
ELOAD_SOURCE,
|
||||
pSW->CV_mode,
|
||||
0x03,
|
||||
0,
|
||||
pSW->source.vc.set_current,
|
||||
pSW->source.set_curr,
|
||||
WORK_START
|
||||
};
|
||||
|
||||
if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) {
|
||||
return -1;
|
||||
}
|
||||
return chrg_sou_com_batch_submit(idx, regs, vals, 6);
|
||||
return chrg_sou_com_batch_submit(idx, regs, vals, 5);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
@@ -57,7 +60,8 @@ int chrg_source_init_submit(rt_uint8_t idx, struct chrg_switch_t *pSW)
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 更新电源运行标志、通道使能、在线状态及work_mode
|
||||
返回说明: 0:初始化命令提交成功 非0:初始化失败
|
||||
其它说明: 成功后状态切换为SOURCE_WORK_WAIT,等待北向返回协商电压
|
||||
其它说明: 标准协议从pd_set准备目标并转入RUNING;快充协议清空旧电压后
|
||||
进入WAIT,等待北向协商结果,INIT本身不写功率板电压
|
||||
*****************************************************************/
|
||||
static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
@@ -65,7 +69,15 @@ static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
int ret;
|
||||
|
||||
/* 只有整批命令成功入队后,才打开通道并进入等待状态。 */
|
||||
/* 最大电流是功率板启动保护值,快充回码到达后可再更新运行目标。 */
|
||||
pSW->source.set_curr = pSW->source.pd_set.mm.max_cur;
|
||||
if (pSW->source.protocol == PRO_NONE) {
|
||||
pSW->source.set_volt = pSW->source.pd_set.mm.max_vol;
|
||||
} else {
|
||||
/* 禁止快充重新启动时沿用上一次协商电压。 */
|
||||
pSW->source.set_volt = 0;
|
||||
}
|
||||
|
||||
ret = chrg_source_init_submit(idx, pSW);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
@@ -75,6 +87,11 @@ static int chrg_source_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
pNOR->enable[idx] = 1;
|
||||
pSOU->online[idx] = 1;
|
||||
chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SOURCE);
|
||||
if (pSW->source.protocol == PRO_NONE) {
|
||||
/* 标准协议没有协商回码,INIT成功后立即由RUNING统一写入电压。 */
|
||||
pSW->source.work_mode = SOURCE_WORK_RUNING;
|
||||
return chrg_source_work_running(idx, pSW);
|
||||
}
|
||||
pSW->source.work_mode = SOURCE_WORK_WAIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -95,17 +112,18 @@ static int chrg_source_work_wait(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
|
||||
/*****************************************************************
|
||||
函数名称: chrg_source_work_running
|
||||
函数描述: 执行电源RUNING状态,下发最新协商目标电压
|
||||
函数描述: 执行电源RUNING状态,下发补偿后的最新目标电压
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: -
|
||||
返回说明: 0:命令提交成功 非0:命令提交失败
|
||||
其它说明: 本状态只写电压寄存器,不重复发送WORK_START
|
||||
其它说明: 功率板设定值固定比目标高200mV,防止限压导致输出进入稳流模式;
|
||||
目标最大值为48000mV,无需做uint16_t饱和处理
|
||||
*****************************************************************/
|
||||
static int chrg_source_work_running(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
/* RUNING只下发协商后的目标电压,不重复发送启动命令。 */
|
||||
/* 只对本次下发值补偿,不修改set_volt,防止多次执行时累计增加。 */
|
||||
rt_uint16_t reg = REG_VOLTAGE_OUT + 1;
|
||||
rt_uint16_t value = pSW->source.vc.set_voltage;
|
||||
rt_uint16_t value = pSW->source.set_volt;
|
||||
|
||||
return chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||||
}
|
||||
@@ -114,9 +132,9 @@ static int chrg_source_work_running(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
函数名称: chrg_source_work_stop
|
||||
函数描述: 执行电源主动关机流程
|
||||
输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体
|
||||
输出参数: 清除运行、使能和在线标志,关闭北向继电器
|
||||
输出参数: 清除目标电压、运行、使能和在线标志,关闭北向继电器
|
||||
返回说明: 0:停止成功 非0:停止命令提交失败
|
||||
其它说明: 成功后状态恢复为SOURCE_WORK_WAIT,等待下一次启动命令
|
||||
其它说明: 先写电压0再发送WORK_STOP;只有整批命令入队成功后才清零set_volt
|
||||
*****************************************************************/
|
||||
static int chrg_source_work_stop(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
@@ -124,15 +142,16 @@ static int chrg_source_work_stop(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
struct chrg_north_t *pNOR = &chrgnorth;
|
||||
int ret;
|
||||
|
||||
rt_uint16_t reg = REG_WORK;
|
||||
rt_uint16_t value = WORK_STOP;
|
||||
rt_uint16_t regs[2] = {REG_VOLTAGE_OUT + 1, REG_WORK};
|
||||
rt_uint16_t vals[2] = {0, WORK_STOP};
|
||||
|
||||
/* 停止命令入队成功后再关闭使能和北向继电器。 */
|
||||
ret = chrg_sou_com_batch_submit(idx, ®, &value, 1);
|
||||
/* 电压清零与停止必须保持顺序,避免下次启动继承旧目标而产生过压。 */
|
||||
ret = chrg_sou_com_batch_submit(idx, regs, vals, 2);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
pSW->source.set_volt = 0;
|
||||
pSW->source.On_Flag = 0;
|
||||
pNOR->enable[idx] = 0;
|
||||
pSOU->online[idx] = 0;
|
||||
@@ -152,17 +171,18 @@ static int chrg_source_work_stop(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
*****************************************************************/
|
||||
static int chrg_source_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW)
|
||||
{
|
||||
rt_uint16_t regs[2] = {REG_REL_ON, REG_WORK};
|
||||
rt_uint16_t vals[2] = {ALL_REL_OFF, WORK_STOP};
|
||||
rt_uint16_t regs[3] = {REG_REL_ON, REG_VOLTAGE_OUT + 1, REG_WORK};
|
||||
rt_uint16_t vals[3] = {ALL_REL_OFF, 0, WORK_STOP};
|
||||
int ret;
|
||||
|
||||
ret = chrg_sou_com_batch_submit(idx, regs, vals, 2);
|
||||
ret = chrg_sou_com_batch_submit(idx, regs, vals, 3);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 停止成功入队后,清除旧Sink运行标志。 */
|
||||
pSW->sink.On_work = 0;
|
||||
pSW->source.set_volt = 0;
|
||||
/* 首次进入Source时必须从CC线配置开始,不能沿用Sink的sub状态。 */
|
||||
pSW->sub = IDX_SET_SOURCE_CC_SET;
|
||||
/* SWITCH只负责旧角色退出,后续启动统一交给Source INIT状态。 */
|
||||
@@ -891,6 +911,8 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_
|
||||
|
||||
rt_uint8_t idx = start_idx;
|
||||
struct chrg_src_t *source = &psw->source;
|
||||
const struct vc_pd_t *pd = &source->pd_set;
|
||||
const struct vc_mm_t *mm = &pd->mm;
|
||||
// 1. src + pps(2字节)
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
@@ -901,23 +923,23 @@ rt_uint8_t pd_fill_single_group_need_src_com(rt_uint8_t *data, rt_uint8_t start_
|
||||
data[idx++] = 0x13;
|
||||
data[idx++] = 0x88;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
data[idx++] = source->src;
|
||||
data[idx++] = source->pps;
|
||||
rt_kprintf("src = %d pps = %d\n",source->src,source->pps);
|
||||
data[idx++] = pd->src_type;
|
||||
data[idx++] = pd->pps_type;
|
||||
//rt_kprintf("src = %d pps = %d\n", pd->src_type, pd->pps_type);
|
||||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->min_vol >> 8;
|
||||
data[idx++] = source->min_vol & 0xFF;
|
||||
data[idx++] = mm->min_vol >> 8;
|
||||
data[idx++] = mm->min_vol & 0xFF;
|
||||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_voltage >> 8;
|
||||
data[idx++] = source->vc.set_voltage & 0xFF;
|
||||
data[idx++] = mm->max_vol >> 8;
|
||||
data[idx++] = mm->max_vol & 0xFF;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
@@ -928,28 +950,30 @@ rt_uint8_t pd_fill_single_group_no_src_com(rt_uint8_t *data, rt_uint8_t start_id
|
||||
|
||||
rt_uint8_t idx = start_idx;
|
||||
struct chrg_src_t *source = &psw->source;
|
||||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||||
// 1. src + pps(2字节)
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->min_vol >> 8;
|
||||
data[idx++] = source->min_vol & 0xFF;
|
||||
data[idx++] = mm->min_vol >> 8;
|
||||
data[idx++] = mm->min_vol & 0xFF;
|
||||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_voltage >> 8;
|
||||
data[idx++] = source->vc.set_voltage & 0xFF;
|
||||
data[idx++] = mm->max_vol >> 8;
|
||||
data[idx++] = mm->max_vol & 0xFF;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
return idx - start_idx; // 返回填充的总字节数
|
||||
}
|
||||
|
||||
rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||||
rt_uint8_t pd_fill_single_group_AFC(rt_uint8_t *data, rt_uint8_t start_idx,struct chrg_switch_t *psw){
|
||||
|
||||
rt_uint8_t idx = start_idx;
|
||||
struct chrg_src_t *source = &psw->source;
|
||||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||||
// 1. src + pps(2字节)
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
@@ -960,8 +984,8 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s
|
||||
data[idx++] = 0x13;
|
||||
data[idx++] = 0x88;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
@@ -969,14 +993,14 @@ rt_uint8_t pd_fill_single_group_FCP_AFC(rt_uint8_t *data, rt_uint8_t start_idx,s
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_voltage >> 8;
|
||||
data[idx++] = source->vc.set_voltage & 0xFF;
|
||||
data[idx++] = mm->max_vol >> 8;
|
||||
data[idx++] = mm->max_vol & 0xFF;
|
||||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_voltage >> 8;
|
||||
data[idx++] = source->vc.set_voltage & 0xFF;
|
||||
data[idx++] = mm->max_vol >> 8;
|
||||
data[idx++] = mm->max_vol & 0xFF;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
@@ -987,6 +1011,7 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
|
||||
|
||||
rt_uint8_t idx = start_idx;
|
||||
struct chrg_src_t *source = &psw->source;
|
||||
const struct vc_mm_t *mm = &source->pd_set.mm;
|
||||
// 1. src + pps(2字节)
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
@@ -997,8 +1022,8 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
|
||||
data[idx++] = 0x13;
|
||||
data[idx++] = 0x88;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
@@ -1006,20 +1031,45 @@ rt_uint8_t pd_fill_single_group_UFCS(rt_uint8_t *data, rt_uint8_t start_idx,stru
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
// 2. 最小电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->min_vol >> 8;
|
||||
data[idx++] = source->min_vol & 0xFF;
|
||||
data[idx++] = mm->min_vol >> 8;
|
||||
data[idx++] = mm->min_vol & 0xFF;
|
||||
// 3. 最大电压(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_voltage >> 8;
|
||||
data[idx++] = source->vc.set_voltage & 0xFF;
|
||||
data[idx++] = mm->max_vol >> 8;
|
||||
data[idx++] = mm->max_vol & 0xFF;
|
||||
// 4. 电流/功率(高+低,直接取已拆分好的值)
|
||||
data[idx++] = source->vc.set_current >> 8;
|
||||
data[idx++] = source->vc.set_current & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
// 5. 保留位6字节(直接填0)
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx+=6;
|
||||
return idx - start_idx; // 返回填充的总字节数
|
||||
}
|
||||
|
||||
static rt_uint8_t chrg_source_fill_AFC_three_gears(rt_uint8_t *data,
|
||||
rt_uint8_t start_idx, struct chrg_switch_t *psw)
|
||||
{
|
||||
static const rt_uint16_t fixed_voltages[] = {5000U, 9000U, 12000U, 20000U};
|
||||
const struct vc_mm_t *mm = &psw->source.pd_set.mm;
|
||||
rt_uint8_t idx = start_idx;
|
||||
rt_uint8_t gear;
|
||||
|
||||
for (gear = 0; gear < (sizeof(fixed_voltages) / sizeof(fixed_voltages[0]));
|
||||
gear++) {
|
||||
/* FCP固定电压档不使用PD源类型和PPS类型。 */
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = 0x00;
|
||||
data[idx++] = fixed_voltages[gear] >> 8;
|
||||
data[idx++] = fixed_voltages[gear] & 0xFF;
|
||||
data[idx++] = fixed_voltages[gear] >> 8;
|
||||
data[idx++] = fixed_voltages[gear] & 0xFF;
|
||||
data[idx++] = mm->max_cur >> 8;
|
||||
data[idx++] = mm->max_cur & 0xFF;
|
||||
memset(&data[idx], 0x00, 6);
|
||||
idx += 6;
|
||||
}
|
||||
|
||||
return idx - start_idx;
|
||||
}
|
||||
|
||||
int source_set_pro(rt_uint8_t pro, struct chrg_switch_t *pSW)
|
||||
{
|
||||
@@ -1032,14 +1082,14 @@ int source_set_pro(rt_uint8_t pro, struct chrg_switch_t *pSW)
|
||||
rt_uint8_t idx = 1; //从data[1]开始填充
|
||||
rt_uint8_t fill_len = 0;
|
||||
rt_uint8_t protocal = pSW->source.protocol;
|
||||
if(protocal == 0x0A){
|
||||
if(protocal == PRO_PD0PSS){
|
||||
fill_len = pd_fill_single_group_need_src_com(data, idx, pSW);
|
||||
}else if(protocal == 0x03||protocal == 0x07||protocal == 0x08 ){
|
||||
}else if(protocal == PRO_SCPB||protocal == PRO_QC30||protocal == PRO_QC20 ||protocal == PRO_FCP ){
|
||||
fill_len = pd_fill_single_group_no_src_com(data, idx, pSW);
|
||||
}else if(protocal == 0x0C){
|
||||
}else if(protocal == PRO_UFCS){
|
||||
fill_len = pd_fill_single_group_UFCS(data, idx, pSW);
|
||||
}else{
|
||||
fill_len = pd_fill_single_group_FCP_AFC(data, idx, pSW);
|
||||
fill_len = chrg_source_fill_AFC_three_gears(data, idx, pSW);
|
||||
}
|
||||
idx += fill_len;
|
||||
send_len = idx; // 总填充字节数
|
||||
|
||||
@@ -137,8 +137,6 @@ struct set_qc_ack_t {
|
||||
|
||||
struct src_vc_t {
|
||||
rt_uint16_t voltage; // 读取 0.01V
|
||||
rt_uint16_t set_voltage; // 设置电压 mV
|
||||
rt_uint16_t set_current; // 设置电流 mA
|
||||
rt_uint16_t version; // 版本号
|
||||
};
|
||||
|
||||
@@ -146,20 +144,18 @@ struct src_vc_t {
|
||||
// source 参数结构
|
||||
struct chrg_src_t {
|
||||
eSRC_PRO protocol; // 协议类型
|
||||
rt_uint8_t src; // 源类型
|
||||
rt_uint8_t pps; // PPS类型
|
||||
rt_uint8_t pro_gear_idx; // 挡位
|
||||
rt_uint16_t min_vol; // 最小电压 mV
|
||||
rt_uint8_t vol_lvl; // CC线电平
|
||||
rt_uint8_t cc_set; // cc线选择 //0代表1+2,1代表cc1,2代表cc2
|
||||
rt_uint8_t CC_Set; // CC线选择:0=CC1+CC2,1=CC1,2=CC2
|
||||
rt_uint8_t Now_State; // 当前状态
|
||||
rt_uint8_t On_Flag; // 启动总标志(0/1)
|
||||
rt_uint8_t LCD_Set_Pro_Flag; // LCD设置协议标志位
|
||||
rt_uint8_t change_sink_Flag; // 从source切换到sink标志位
|
||||
rt_uint8_t work_mode;
|
||||
struct src_vc_t vc; // 读取数据
|
||||
rt_uint16_t set_volt; // 北向解析后准备写入功率板的目标电压(mV)
|
||||
rt_uint16_t set_curr; // 北向解析后准备写入功率板的目标电流(mA)
|
||||
struct src_vc_t vc; // 北向回读数据
|
||||
struct vc_pd_t pd_get[2]; // 读取PD协议数据
|
||||
struct vc_pd_t pd_set[2]; // 设置PD协议数据
|
||||
struct vc_pd_t pd_set; // COM设置的协议挡位、类型和电压电流范围
|
||||
};
|
||||
// 电源工作状态机:COM只切换状态,具体功率板指令由状态处理函数下发
|
||||
enum {
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
# 四通道自举老化测试计划
|
||||
|
||||
## 1. 测试目的
|
||||
|
||||
验证四通道在源载自连接条件下长期运行的稳定性,重点覆盖:
|
||||
|
||||
- Source/Sink启动、停止及角色切换流程;
|
||||
- 标准、PD、QC、FCP、AFC及UFCS等已实现协议的协商稳定性;
|
||||
- 四通道连续控制、南向指令执行及量测轮询稳定性;
|
||||
- 电压、电流阶梯变化和长时间带载能力;
|
||||
- 通信超时、协议掉线、功率板故障、异常复位和温升等问题。
|
||||
|
||||
本计划不包含短路和OCP破坏性测试。此类项目应使用独立限流电源、专用线材及人员值守,不能混入无人值守老化。
|
||||
|
||||
## 2. 测试连接
|
||||
|
||||
### 2.1 第一组连接
|
||||
|
||||
| 回路 | Source通道 | Sink通道 | 连接方式 |
|
||||
| --- | --- | --- | --- |
|
||||
| A | CH1 | CH2 | VBUS、GND及协议线完整连接 |
|
||||
| B | CH3 | CH4 | VBUS、GND及协议线完整连接 |
|
||||
|
||||
### 2.2 反向角色连接
|
||||
|
||||
完成正向老化后不改变线束,停止全部通道并交换角色:
|
||||
|
||||
| 回路 | Source通道 | Sink通道 |
|
||||
| --- | --- | --- |
|
||||
| A | CH2 | CH1 |
|
||||
| B | CH4 | CH3 |
|
||||
|
||||
线束必须满足目标电流要求。PD测试连接CC,QC/FCP/AFC测试连接D+、D-,并保证协议板GND与功率GND连接符合硬件设计。严禁两个Source输出直接相连。
|
||||
|
||||
## 3. 测试条件
|
||||
|
||||
- 使用待发布版本的主控、Source协议板、Sink协议板和功率板固件;
|
||||
- 记录固件版本、硬件版本、设备序列号、线材规格及环境温度;
|
||||
- 风扇、保险丝、急停和输入电源工作正常;
|
||||
- 输入电源功率至少保留20%余量;
|
||||
- 测试电流不得超过连接器、线材、功率板和协议档位中的最小额定值;
|
||||
- 常规量测查询周期设为1秒,状态及故障寄存器至少每5秒记录一次;
|
||||
- 30ms查询仅用于不超过60秒的波形专项采样,结束后恢复1秒周期;
|
||||
- 上位机必须收到并校验上一条Modbus响应后再发送下一条命令;
|
||||
- Modbus异常响应必须单独记录,特别是异常码`0x06`(设备忙)。
|
||||
|
||||
## 4. 单回路启动流程
|
||||
|
||||
每次启动必须按照以下顺序执行:
|
||||
|
||||
1. 向Source和Sink发送停止,确认功率板工作状态为停止;
|
||||
2. 设置Source角色、协议、协议档位、最大电压、最大电流及CC线;
|
||||
3. 设置Sink角色、协议、申请电压、申请电流、恒流模式及负载电流;
|
||||
4. 对Source执行参数生效并启动;
|
||||
5. 对Sink执行参数生效并启动;
|
||||
6. 等待协议协商和南向功率板命令实际执行,不能将COM响应当作输出已经生效;
|
||||
7. 连续读取量测值,电压稳定并保持3次有效采样后再进入老化计时;
|
||||
8. 启动失败时先停止Sink,再停止Source,禁止直接反复发送启动命令。
|
||||
|
||||
正常停止顺序为:Sink停止并确认电流下降,然后Source停止并确认电压下降,最后才允许切换角色或协议。
|
||||
|
||||
## 5. 判定标准
|
||||
|
||||
### 5.1 单次启动合格条件
|
||||
|
||||
- Source和Sink协议类型与设定一致;
|
||||
- 启动后5秒内进入稳定运行状态;
|
||||
- 稳态电压与目标电压误差不超过200mV;
|
||||
- 稳态电流误差不超过`max(50mA, 设定值的5%)`;
|
||||
- 连续3次采样均满足要求后判定本次启动成功;
|
||||
- 状态和故障寄存器无新增故障位;
|
||||
- 无南向连续3次超时、队列取消、协议掉线或系统复位。
|
||||
|
||||
### 5.2 老化过程停止条件
|
||||
|
||||
出现以下任一情况应立即停止对应回路;出现过压、异味、冒烟或连接器异常发热时停止整机:
|
||||
|
||||
- 电压持续3秒超出目标值±500mV;
|
||||
- 电流持续3秒超出设定值±10%;
|
||||
- 协议掉线后5秒内不能自动恢复;
|
||||
- 功率板报告欠压、过压、过流或其他故障;
|
||||
- 连续3次COM无响应,或出现南向批量命令失败;
|
||||
- 任一通道量测值连续5秒不更新;
|
||||
- 设备复位、线程停止、LED2/LED3长时间停止刷新;
|
||||
- 温度超过器件或整机规格。规格未明确时,连接器和线缆表面达到70摄氏度应停止测试。
|
||||
|
||||
## 6. 48小时老化安排
|
||||
|
||||
### 阶段A:低功率预老化,2小时
|
||||
|
||||
| 时间 | 回路A | 回路B | 目的 |
|
||||
| --- | --- | --- | --- |
|
||||
| 0~1小时 | 标准5V/0.5A | PD 5V/0.5A | 检查基础源载和PD启动 |
|
||||
| 1~2小时 | QC3.0 9V/0.5A | FCP 9V/0.5A | 检查D+/D-协议带载稳定性 |
|
||||
|
||||
每15分钟执行一次停止、等待5秒、重新启动。阶段结束后检查连接器、继电器和线材温升。
|
||||
|
||||
### 阶段B:协议覆盖,6小时
|
||||
|
||||
共执行8个测试时段,每个时段45分钟。两组回路同时使用不同协议;后4个时段交换协议分配,确保两组回路都覆盖全部协议。
|
||||
|
||||
| 时段 | 回路A | 回路B |
|
||||
| --- | --- | --- |
|
||||
| 1 | 标准 | PD固定档 |
|
||||
| 2 | PD PPS | QC2.0 |
|
||||
| 3 | QC3.0 | FCP |
|
||||
| 4 | AFC | UFCS |
|
||||
| 5 | PD固定档 | 标准 |
|
||||
| 6 | QC2.0 | PD PPS |
|
||||
| 7 | FCP | QC3.0 |
|
||||
| 8 | UFCS | AFC |
|
||||
|
||||
每个时段内轮换该协议支持的电压档位,负载电流在0.5A和1A之间交替。协议不支持对应电压时,使用协议实际支持的最近档位。
|
||||
|
||||
| 序号 | 协议 | 电压 | 负载电流 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 标准 | 5V、9V、12V | 0.5A、1A |
|
||||
| 2 | PD固定档 | 5V、9V、12V、15V、20V | 0.5A、1A |
|
||||
| 3 | PD PPS | 5V、9V、12V | 0.5A、1A |
|
||||
| 4 | QC2.0 | 5V、9V、12V | 0.5A、1A |
|
||||
| 5 | QC3.0 | 5V、9V、12V | 0.5A、1A |
|
||||
| 6 | FCP | 5V、9V、12V | 0.5A、1A |
|
||||
| 7 | AFC | 5V、9V、12V | 0.5A、1A |
|
||||
| 8 | UFCS | 按当前固件支持档位 | 0.5A、1A |
|
||||
|
||||
未正式实现或尚未完成硬件验证的协议应标记为“不适用”,不得用其他协议的通过结果代替。
|
||||
|
||||
### 阶段C:额定功率长期运行,20小时
|
||||
|
||||
- 两组回路同时运行;
|
||||
- 优先选择PD 20V和QC3.0 12V两个代表性协议;
|
||||
- 电流按照额定能力的25%、50%、80%循环;
|
||||
- 每个电流档保持30分钟;
|
||||
- 每2小时停止两组回路,等待30秒后重新启动;
|
||||
- 每4小时记录一次主控板、协议板、功率板、连接器和线缆温度;
|
||||
- 第10小时交换两组回路使用的协议,避免固定通道只验证一种协议。
|
||||
|
||||
若设备额定值或散热条件不允许80%档位长时间运行,应以硬件额定连续功率为上限,并在记录中说明限制原因。
|
||||
|
||||
### 阶段D:动态调节与协议重协商,8小时
|
||||
|
||||
每个循环执行以下步骤,循环间隔不得小于30秒:
|
||||
|
||||
1. 在同一协议下按`0.5A -> 1A -> 2A -> 1A -> 0.5A`调节负载;
|
||||
2. 每个电流档保持60秒;
|
||||
3. 固定电流,在协议允许范围内按`5V -> 9V -> 12V -> 9V -> 5V`调节电压;
|
||||
4. 每个电压档稳定后保持60秒;
|
||||
5. 停止Sink,再停止Source;
|
||||
6. 在PD与QC3.0之间切换协议并重新启动;
|
||||
7. 检查切换前输出是否先降为0,以及新协议是否重新协商成功。
|
||||
|
||||
2A仅在源、载、线材及连接器均支持时使用,否则替换为额定电流的80%。
|
||||
|
||||
### 阶段E:角色切换,6小时
|
||||
|
||||
执行200次角色切换动作,即100个完整往返循环:
|
||||
|
||||
1. CH1 Source/CH2 Sink、CH3 Source/CH4 Sink运行60秒;
|
||||
2. 停止Sink并确认电流下降;
|
||||
3. 停止Source并确认电压下降;
|
||||
4. 等待5秒;
|
||||
5. 切换为CH2 Source/CH1 Sink、CH4 Source/CH3 Sink;
|
||||
6. 运行60秒并记录结果;
|
||||
7. 再按相同步骤切换回原角色,完成第二次切换动作和一个完整往返循环。
|
||||
|
||||
每20个完整往返循环更换一次协议,依次使用标准、PD、QC3.0、FCP和AFC。任何一次切换失败都必须保存前后30秒日志。
|
||||
|
||||
### 阶段F:通信和整机重启,6小时
|
||||
|
||||
- 正常运行时每秒读取一次全部四通道量测;
|
||||
- 每10分钟执行一次四通道连续参数设置,命令之间等待Modbus响应;
|
||||
- 四通道参数生效完成后等待300ms,再开始判断量测结果;
|
||||
- 每30分钟执行一次全部停止和重新启动;
|
||||
- 每小时执行一次整机断电重启,断电保持30秒;
|
||||
- 重启后确认四通道初始状态安全,不允许未经上位机启动就输出或带载;
|
||||
- 共完成不少于6次整机断电重启。
|
||||
|
||||
## 7. 数据记录
|
||||
|
||||
老化程序至少保存以下字段,建议使用CSV格式:
|
||||
|
||||
```text
|
||||
timestamp,stage,cycle,pair,source_ch,sink_ch,protocol,
|
||||
target_voltage_mv,target_current_ma,source_voltage_mv,source_current_ma,
|
||||
sink_voltage_mv,sink_current_ma,source_status1,source_status2,
|
||||
sink_status1,sink_status2,source_fault1,source_fault2,
|
||||
sink_fault1,sink_fault2,com_error_count,south_timeout_count,
|
||||
protocol_drop_count,restart_count,board_temp_c,connector_temp_c,result
|
||||
```
|
||||
|
||||
发生异常时额外保存:
|
||||
|
||||
- 异常前后至少30秒的原始COM收发帧;
|
||||
- Source/Sink协议板原始回码;
|
||||
- 南向功率板写命令、响应、重试次数及失败寄存器;
|
||||
- 四通道状态、故障、电压、电流和工作状态机;
|
||||
- 异常时温度、输入电压及现场照片。
|
||||
|
||||
## 8. 最终通过条件
|
||||
|
||||
- 48小时计划全部完成,无安全类故障;
|
||||
- 四个通道均完成Source和Sink角色老化;
|
||||
- 所有声明支持的协议完成正向和反向连接验证;
|
||||
- 200次角色切换动作(100个完整往返循环)无失败;
|
||||
- 不少于6次整机断电重启均正常恢复;
|
||||
- 无不明复位、线程阻塞、量测长期不更新或通道永久失联;
|
||||
- 电压、电流和温升满足本计划判定标准;
|
||||
- 所有异常均有日志、复现条件和明确结论。
|
||||
|
||||
测试完成后形成汇总表,按通道统计启动次数、成功率、协议掉线次数、南向超时次数、最大电压误差、最大电流误差和最高温度。任何未达到100%启动成功率的项目均不得直接判定整机老化通过。
|
||||
Reference in New Issue
Block a user