From 8b7f29d0fc67f589cb07fa13df038d389a8e7795 Mon Sep 17 00:00:00 2001 From: wrh Date: Sat, 8 Aug 2026 20:09:18 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=88=B0V1.1.7=E5=B9=B6=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BD=8E=E7=94=B5=E6=B5=81=E5=BE=85=E6=9C=BA=E4=B8=8E=E5=B9=B6?= =?UTF-8?q?=E8=A1=8C=E6=8F=A1=E6=89=8B=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 关闭南向寄存器写命令调试日志 2. 新增SINK_LOAD_ENABLE_MIN_MA宏限制最低带载电流为100mA 3. 新增SINK_WORK_LOAD_STANDBY等4种低电流待机工作状态 4. 重构协议电压/电流变化处理逻辑,改为软卸载不切继电器 5. 实现南北向握手并行执行,降低0x20查询频率 6. 新增chrg_sink_load_should_start和chrg_sink_handshake_north_ready接口 7. 优化RUNING状态命令顺序,避免主继电器重复断开 8. 更新编译日志,修正代码尺寸数据 --- apps/chrg/applications/thread/chrg_comm.c | 108 ++++- apps/chrg/applications/thread/chrg_north.c | 21 +- apps/chrg/applications/thread/chrg_north.h | 2 +- apps/chrg/applications/thread/chrg_roll_nor.c | 136 ++++++- apps/chrg/applications/utils/chrg_sink.c | 371 +++++++++++++----- apps/chrg/applications/utils/chrg_sink.h | 20 +- apps/chrg/codex_build.log | 14 +- docs/修改日志.md | 162 ++++++++ 8 files changed, 676 insertions(+), 158 deletions(-) diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index f257d3a..27832af 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -100,6 +100,9 @@ static void chrg_mb_write_src(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_t sou_value, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR, struct chrg_south_t *pSOU); static int chrg_sink_diff_send_reg(eIDX_SOU_CH ch, const chrg_param_diff_t *pDiff, struct chrg_switch_t *pReal); +static rt_bool_t chrg_comm_handle_sink_load_current( + const chrg_param_diff_t *pDiff, rt_uint8_t old_work_mode, + struct chrg_switch_t *pReal); /*! \brief Function to set bits in a byte buffer. * @@ -2338,23 +2341,31 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, { rt_bool_t full_handshake_change; rt_bool_t protocol_voltage_only; + rt_bool_t protocol_current_change; + rt_bool_t protocol_data_changed; rt_uint8_t curr_test; rt_uint8_t curr_test_old; rt_uint8_t old_cv_mode = pReal->CV_mode; rt_uint16_t old_loadv = pReal->sink.loadv; rt_uint16_t old_loadc = pReal->sink.loadc; + rt_uint8_t old_work_mode = pReal->sink.work_mode; rt_uint16_t sink_work = pShadow->sink.Now_State; chrg_param_diff_t diff_info; chrg_comm_get_param_diff(ID_SINK, pReal, pShadow, &diff_info); /* - * 协议类型、CC、协议组号或协议电流变化都按完整重握手处理。 - * 只有单独修改协议电压时才允许仅掉载而不切换南向继电器。 + * 协议类型、CC和协议组号变化需要完整握手;协议电压和协议电流 + * 变化只需要软卸载后重发协议,不关闭南向继电器。 */ full_handshake_change = diff_info.protocol_changed || diff_info.cc_changed || - diff_info.group_changed || diff_info.pro_current_changed; - protocol_voltage_only = diff_info.pro_voltage_changed && + diff_info.group_changed; + protocol_data_changed = diff_info.protocol_changed || + diff_info.group_changed || diff_info.pro_voltage_changed || + diff_info.pro_current_changed; + protocol_current_change = diff_info.pro_current_changed && !full_handshake_change; + protocol_voltage_only = diff_info.pro_voltage_changed && + !full_handshake_change && !protocol_current_change; rt_memcpy(pReal, pShadow, sizeof(struct chrg_switch_t)); if (sink_work == 0x01) { @@ -2380,14 +2391,38 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, pReal->sub = IDX_SET_SINK_PD; pReal->sink.work_mode = SINK_WORK_INIT; } else if (full_handshake_change) { - /* 协议类型或CC变化需要重发协议和CC;仅组号/协议电流变化只重发协议。 */ - pReal->sub = (diff_info.protocol_changed || diff_info.cc_changed) ? - IDX_SET_SINK_PD : IDX_SET_SINK_PD_ONLY; + /* + * 只有CC实际变化时才发送目标CC命令并等待;协议类型或组号 + * 单独变化时直接重发PD帧,不重复设置未变化的CC。 + * 协议与CC同时变化时先发送协议,协议应答后再设置目标CC; + * 仅协议变化时不重复设置未变化的CC。 + */ + if (diff_info.cc_changed && protocol_data_changed) { + pReal->sub = IDX_SET_SINK_PD; + } else if (diff_info.cc_changed) { + pReal->sub = IDX_SET_SINK_CCLINE; + } else { + pReal->sub = IDX_SET_SINK_PD_ONLY; + } pReal->sink.work_mode = SINK_WORK_HANDSHAKE_PREPARE; - } else if (protocol_voltage_only) { - /* 仅协议电压变化时保持主副继电器状态,只停止负载并清零电流。 */ + } else if (protocol_voltage_only || protocol_current_change) { + /* + * 协议电压、协议电流变化都只执行软卸载,不关闭南向继电器。 + * 低电流待机本身已经WORK_STOP,无需重复提交卸载命令;运行中 + * 则等待实际电流降到安全范围后再重发协议。 + */ pReal->sub = IDX_SET_SINK_PD_ONLY; - pReal->sink.work_mode = SINK_WORK_PROTOCOL_UNLOAD; + if (old_work_mode == SINK_WORK_LOAD_STANDBY) { + pReal->sink.work_mode = SINK_WORK_WAIT; + } else if (old_work_mode == SINK_WORK_LOAD_SOFT_STANDBY) { + pReal->sink.work_mode = SINK_WORK_SOFT_RESUME_WAIT; + } else { + /* 运行状态修改协议参数时保持继电器,只停止电子负载。 */ + pReal->sink.work_mode = SINK_WORK_PROTOCOL_UNLOAD; + } + } else if (chrg_comm_handle_sink_load_current(&diff_info, + old_work_mode, pReal)) { + /* 电流跨门限的停止或恢复已转换为独立Sink状态,由统一入口下发。 */ } else if (chrg_sink_diff_send_reg((eIDX_SOU_CH)ch, &diff_info, pReal) != 0) { pReal->CV_mode = old_cv_mode; @@ -2404,6 +2439,59 @@ static eMBException chrg_comm_apply_sink_effect(rt_uint8_t ch, MB_EX_NONE : MB_EX_SLAVE_BUSY; } +/***************************************************************** +函数名称: chrg_comm_handle_sink_load_current +函数描述: 处理普通负载电流跨越最低带载门限时的状态转换 +输入参数: pDiff:本次参数差异 old_work_mode:生效前工作状态 + pReal:已复制新参数的运行结构体 +输出参数: 必要时更新sink.work_mode +返回说明: RT_TRUE:本次电流变化已处理,禁止再直接写电流寄存器 + RT_FALSE:未跨门限,继续执行普通差异下发 +其它说明: 北向协议、CC和协议电流变化在调用本函数前处理;本函数只管理 + 南向电子负载的WORK_STOP/CURRENT=0及无握手快速恢复 +*****************************************************************/ +static rt_bool_t chrg_comm_handle_sink_load_current( + const chrg_param_diff_t *pDiff, rt_uint8_t old_work_mode, + struct chrg_switch_t *pReal) +{ + rt_bool_t should_start; + + if ((pDiff == RT_NULL) || (pReal == RT_NULL) || + !pDiff->current_changed || + (pReal->CV_mode != MODE_CONSTANT_CURRENT)) { + return RT_FALSE; + } + should_start = chrg_sink_load_should_start(pReal); + + if ((old_work_mode == SINK_WORK_RUNING) || + (old_work_mode == SINK_WORK_SOFT_RUNNING)) { + if (!should_start) { + pReal->sink.work_mode = SINK_WORK_LOAD_STOP; + return RT_TRUE; + } + return RT_FALSE; + } + + if (old_work_mode == SINK_WORK_LOAD_STANDBY) { + if (should_start) { + /* 独立入口可避开RUNING相同状态去重,并执行完整继电器启动。 */ + pReal->sink.work_mode = SINK_WORK_LOAD_START; + } + return RT_TRUE; + } + + if (old_work_mode == SINK_WORK_LOAD_SOFT_STANDBY) { + if (should_start) { + /* 继电器和协议保持不变,只恢复目标电流和WORK_START。 */ + pReal->sink.work_mode = SINK_WORK_LOAD_RESUME; + } + return RT_TRUE; + } + + /* 协议握手期间禁止把低于门限的小电流提前写入南向功率板。 */ + return should_start ? RT_FALSE : RT_TRUE; +} + /***************************************************************** 函数名称: chrg_comm_apply_source_effect 函数描述: 处理COM参数生效后的同角色电源启停和参数差异更新 diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 9ca6584..227d2d1 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -29,7 +29,7 @@ #define SOURCE_QC_MIN_VOLT_MV 5000U // QC2.0/QC3.0允许使用的最低目标电压 #define SOURCE_QC_SWITCH_ERROR 0x04U // Source协议或CC切换失败错误位 #define SINK_CURRENT_START_GRACE_MS 200U // Sink启动后暂不判断无电流的保护时间 -#define SINK_VOLT_STABLE_CONFIRM_COUNT 2U // Sink进入RUNING前连续稳定电压帧数 +#define SINK_VOLT_STABLE_CONFIRM_COUNT 0U // Sink一帧有效稳定电压即进入RUNING /***************************************************************** 函数名称: chrg_source_apply_protocol_voltage_rule @@ -193,7 +193,7 @@ void chrg_source_setting(rt_uint8_t *frame_data, eIDX_SOU_CH idx, 输出参数: 更新VZ、VF、低压计数、稳定电压计数、无电流计数及sink.work_mode 返回说明: - 其它说明: 电压连续低于门槛进入LOW;掉电处理恢复副继电器后,电压重新 - 出现时先重设协议和CC;连续两次达到目标附近才进入RUNING + 出现时先重设协议和CC;一帧有效电压达到目标附近即进入RUNING *****************************************************************/ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, struct chrg_switch_t *pSW, struct chrg_north_t *pNOR) @@ -220,7 +220,7 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, if (volt_mv <= WORK_MIN_VOLT) { // 电压过低,禁止进入工作状态机 volt_stable_count[idx] = 0; if (volt_set_ok[idx] == 1) { - if (++volt_low[idx] >= 2) { + if (++volt_low[idx] >= 100) { volt_set_ok[idx] = 0; no_curr[idx] = 0; pSW->sink.work_mode = SINK_WORK_LOW; @@ -245,13 +245,15 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, no_curr[idx] = 0; } else if ((rt_uint32_t)volt_mv + 2000 >= pSW->sink.pro_loadv) { if ((pSW->sink.work_mode != SINK_WORK_RUNING) && - (pSW->sink.work_mode != SINK_WORK_SOFT_RUNNING)) { + (pSW->sink.work_mode != SINK_WORK_SOFT_RUNNING) && + (pSW->sink.work_mode != SINK_WORK_LOAD_STANDBY) && + (pSW->sink.work_mode != SINK_WORK_LOAD_SOFT_STANDBY)) { if (volt_stable_count[idx] < SINK_VOLT_STABLE_CONFIRM_COUNT) { volt_stable_count[idx]++; } if (volt_stable_count[idx] >= SINK_VOLT_STABLE_CONFIRM_COUNT) { - /* 连续两次北向量测均达到目标电压附近后才允许带载,避免 - * 单次瞬态电压或旧回码导致负载提前进入RUNING。 */ + /* 回码已经过CRC、ID、命令和配置版本校验;首帧达到目标 + * 电压附近后立即进入RUNING,不再增加额外稳定等待。 */ volt_stable_count[idx] = 0; pSW->sink.work_mode = (pSW->sink.work_mode == SINK_WORK_SOFT_RESUME_WAIT) ? @@ -259,8 +261,13 @@ void chrg_sink_parse(rt_uint8_t *frame_data, eIDX_SOU_CH idx, running_start_tick[idx] = rt_tick_get(); no_curr[idx] = 0; } + } else if ((pSW->sink.work_mode == SINK_WORK_LOAD_STANDBY) || + (pSW->sink.work_mode == SINK_WORK_LOAD_SOFT_STANDBY)) { + /* 协议保持在线但电子负载主动停止,不执行无电流重试。 */ + volt_stable_count[idx] = 0; + no_curr[idx] = 0; } else if ((pSW->Now_current > 200) || - (pSW->sink.pro_loadc < 200)) { + (pSW->sink.loadc < 200)) { volt_stable_count[idx] = 0; no_curr[idx] = 0; } else if ((rt_tick_t)(rt_tick_get() - running_start_tick[idx]) >= diff --git a/apps/chrg/applications/thread/chrg_north.h b/apps/chrg/applications/thread/chrg_north.h index b3c9a78..fb6fc7e 100644 --- a/apps/chrg/applications/thread/chrg_north.h +++ b/apps/chrg/applications/thread/chrg_north.h @@ -26,7 +26,7 @@ #define NORTH_SOURCE_DEBUG 0x00 // Source协议解析及组帧 #define NORTH_SINK_DEBUG 0x00 // Sink协议解析及组帧 #define SOUTH_FRAME_DEBUG 0x00 // 南向UART原始收发帧 -#define SOUTH_COMMAND_DEBUG 0x01 // 南向寄存器写命令 +#define SOUTH_COMMAND_DEBUG 0x00 // 南向寄存器写命令 #define COMM_FRAME_DEBUG 0x00 // COM UART原始收发帧 #define COMM_DEBUG 0x00 // COM寄存器读写过程 #define COMM_TRIM_DEBUG 0x00 // COM校准参数解析 diff --git a/apps/chrg/applications/thread/chrg_roll_nor.c b/apps/chrg/applications/thread/chrg_roll_nor.c index fd8e02a..65cdcc7 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.c +++ b/apps/chrg/applications/thread/chrg_roll_nor.c @@ -33,7 +33,9 @@ #define SOURCE_CC_CLOSE_VALUE 0x03U // 0x17命令参数:同时断开CC1和CC2 #define SOURCE_CC_CLOSE_WAIT_MS 300U // 本轮所有CC_CLOSE应答后的共享保护时间 #define SOURCE_PROTOCOL_WAIT_MS 100U // 每通道0xD0应答后的协议生效保护时间 -#define SINK_CC_STABLE_WAIT_MS 50U // Sink设置目标CC应答后的非阻塞稳定时间 +#define SINK_CC_WAIT_MS 200U // Sink设置目标CC应答后的非阻塞保护时间 +#define SINK_HANDSHAKE_FIRST_QUERY_DELAY_MS 50U // 协议/CC回码后首条0x20的等待时间 +#define SINK_HANDSHAKE_QUERY_INTERVAL_MS 50U // 握手未完成时后续0x20查询间隔 #define SOURCE_CHANNEL_BIT(ch) ((rt_uint8_t)(1U << (ch))) const rt_base_t sw_uart[TOTAL_NOR_CHS] = { IDX_GPO_UART_SW1, @@ -58,6 +60,49 @@ static rt_uint8_t g_source_protocol_wait_mask = 0U; static rt_tick_t g_source_protocol_wait_start[TOTAL_NOR_CHS] = {0}; static rt_uint8_t g_sink_cc_wait_mask = 0U; static rt_tick_t g_sink_cc_wait_start[TOTAL_NOR_CHS] = {0}; +/* Sink协议/CC握手期间的0x20查询节流记录,按通道独立计时。 */ +static rt_bool_t g_sink_query_throttle[TOTAL_NOR_CHS] = {RT_FALSE}; +static rt_bool_t g_sink_query_first_pending[TOTAL_NOR_CHS] = {RT_FALSE}; +static rt_tick_t g_sink_query_tick[TOTAL_NOR_CHS] = {0}; + +/***************************************************************** +函数名称: chrg_roll_nor_sink_query_is_slow +函数描述: 判断当前Sink状态是否仍处于协议握手量测阶段 +输入参数: pSW:当前负载通道控制结构体 +输出参数: - +返回说明: RT_TRUE:0x20查询按握手节奏发送 RT_FALSE:使用正常轮询周期 +其它说明: 只有协议/CC设置后等待协商电压的阶段限速;RUNING和低电流 + 待机不受影响,避免影响正常量测刷新速度 +*****************************************************************/ +static rt_bool_t chrg_roll_nor_sink_query_is_slow( + const struct chrg_switch_t *pSW) +{ + if (pSW == RT_NULL) { + return RT_FALSE; + } + return (pSW->sink.work_mode == SINK_WORK_WAIT) || + (pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) || + (pSW->sink.work_mode == SINK_WORK_SOFT_RESUME_WAIT) || + (pSW->sink.work_mode == SINK_WORK_LOW_MONITOR); +} + +/***************************************************************** +函数名称: chrg_roll_nor_sink_query_wait_start +函数描述: 启动Sink握手阶段的0x20查询节流计时 +输入参数: ch:北向通道编号 +输出参数: 记录当前tick并开启节流 +返回说明: - +其它说明: 协议或CC回码成功后调用,避免下一轮立即查询协议板 +*****************************************************************/ +static void chrg_roll_nor_sink_query_wait_start(rt_uint8_t ch) +{ + if (ch >= TOTAL_NOR_CHS) { + return; + } + g_sink_query_throttle[ch] = RT_TRUE; + g_sink_query_first_pending[ch] = RT_TRUE; + g_sink_query_tick[ch] = rt_tick_get(); +} /***************************************************************** 函数名称: chrg_roll_nor_source_switch_reset @@ -220,12 +265,12 @@ static void chrg_roll_nor_sink_cc_wait_start(rt_uint8_t ch) /***************************************************************** 函数名称: chrg_roll_nor_sink_wait_process -函数描述: 管理Sink副继电器确认、安全卸载和CC设置后的稳定等待 +函数描述: 管理Sink安全卸载、南北并行握手和CC设置后的稳定等待 输入参数: ch:北向通道编号 pSW:通道实时控制结构体 -输出参数: 南向卸载完成后允许发送协议;CC稳定时间到达后切换为电压查询 +输出参数: 南向批次完成后允许协议/CC;低电流和CC均满足后允许查询 返回说明: RT_TRUE:本轮仍需等待,不发送北向命令 RT_FALSE:可继续发送 -其它说明: INIT只等待第一条FU_REL_ON完成;其余初始化命令入队后与北向 - 握手并行。软卸载和完整重握手仍必须完成低电流确认后才放行 +其它说明: 完整重握手中,南向批次完成后协议/CC与低电流确认并行; + 进入GET_SINK_VC后,必须等低电流确认完成才允许发送0x20 *****************************************************************/ static rt_bool_t chrg_roll_nor_sink_wait_process(rt_uint8_t ch, struct chrg_switch_t *pSW) @@ -241,35 +286,80 @@ static rt_bool_t chrg_roll_nor_sink_wait_process(rt_uint8_t ch, if ((pSW->id != ID_SINK) || !pSW->sink.On_work) { g_sink_cc_wait_mask &= (rt_uint8_t)~bit; g_sink_cc_wait_start[ch] = 0U; + g_sink_query_throttle[ch] = RT_FALSE; + g_sink_query_first_pending[ch] = RT_FALSE; + g_sink_query_tick[ch] = 0U; return RT_FALSE; } - /* 副继电器或安全卸载尚未确认时,禁止任何北向设置和电压查询。 */ - if ((pSW->sink.work_mode == SINK_WORK_INIT_AUX_WAIT) || - (pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) || - (pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT) || - (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT)) { + /* 普通软卸载和低电流恢复仍禁止北向;INIT_AUX_WAIT允许南北向并行。 */ + if ((pSW->sink.work_mode == SINK_WORK_UNLOAD_WAIT) || + (pSW->sink.work_mode == SINK_WORK_LOW_AUX_WAIT)) { return RT_TRUE; } + /* + * 完整握手批次最后发送FU_REL_ON。批次完成并建立量测基线后, + * 允许北向协议/CC与南向低电流确认并行;当sub进入GET_SINK_VC + * 而状态仍为HANDSHAKE_WAIT时,说明低电流确认尚未完成,禁止发送0x20。 + */ + if (pSW->sink.work_mode == SINK_WORK_HANDSHAKE_WAIT) { + if (!chrg_sink_handshake_north_ready((eIDX_SOU_CH)ch)) { + return RT_TRUE; + } + if (pSW->sub == IDX_GET_SINK_VC) { + return RT_TRUE; + } + } + if (pSW->sub != IDX_WAIT_SINK_CC) { /* COM在等待期间提交新配置时,清理旧事务留下的CC计时记录。 */ g_sink_cc_wait_mask &= (rt_uint8_t)~bit; g_sink_cc_wait_start[ch] = 0U; - return RT_FALSE; - } + if (!chrg_roll_nor_sink_query_is_slow(pSW)) { + g_sink_query_throttle[ch] = RT_FALSE; + g_sink_query_first_pending[ch] = RT_FALSE; + g_sink_query_tick[ch] = 0U; + } + } else { + if ((g_sink_cc_wait_mask & bit) == 0U) { + pSW->sub = IDX_GET_SINK_VC; + chrg_roll_nor_sink_query_wait_start(ch); + return RT_TRUE; + } + elapsed = (rt_tick_t)(rt_tick_get() - g_sink_cc_wait_start[ch]); + if (elapsed < rt_tick_from_millisecond(SINK_CC_WAIT_MS)) { + return RT_TRUE; + } - if ((g_sink_cc_wait_mask & bit) == 0U) { + /* 协议已先设置;CC应答并完成保护等待后进入电压查询。 */ + g_sink_query_throttle[ch] = RT_TRUE; + g_sink_query_first_pending[ch] = RT_TRUE; + g_sink_query_tick[ch] = g_sink_cc_wait_start[ch]; + g_sink_cc_wait_mask &= (rt_uint8_t)~bit; + g_sink_cc_wait_start[ch] = 0U; pSW->sub = IDX_GET_SINK_VC; - return RT_FALSE; - } - elapsed = (rt_tick_t)(rt_tick_get() - g_sink_cc_wait_start[ch]); - if (elapsed < rt_tick_from_millisecond(SINK_CC_STABLE_WAIT_MS)) { return RT_TRUE; } - g_sink_cc_wait_mask &= (rt_uint8_t)~bit; - g_sink_cc_wait_start[ch] = 0U; - pSW->sub = IDX_GET_SINK_VC; + /* 首条0x20等待200ms;握手未稳定时,后续查询间隔缩短为100ms。 */ + if (chrg_roll_nor_sink_query_is_slow(pSW) && + (pSW->sub == IDX_GET_SINK_VC)) { + rt_uint32_t query_interval_ms; + + if (!g_sink_query_throttle[ch]) { + chrg_roll_nor_sink_query_wait_start(ch); + return RT_TRUE; + } + query_interval_ms = g_sink_query_first_pending[ch] ? + SINK_HANDSHAKE_FIRST_QUERY_DELAY_MS : + SINK_HANDSHAKE_QUERY_INTERVAL_MS; + elapsed = (rt_tick_t)(rt_tick_get() - g_sink_query_tick[ch]); + if (elapsed < rt_tick_from_millisecond(query_interval_ms)) { + return RT_TRUE; + } + g_sink_query_first_pending[ch] = RT_FALSE; + g_sink_query_tick[ch] = rt_tick_get(); + } return RT_FALSE; } /***************************************************************** @@ -665,7 +755,7 @@ static int chrg_roll_nor_cmd (struct chrg_rollnor_t *pROLL) 返回说明: >0:发送长度 <0:发送失败或状态不支持 其它说明: Source按差异执行协议、CC或组合命令;涉及PD的运行中切换先发送CC_CLOSE; 停止状态启动和主动停止均不额外发送CC_CLOSE; - Sink依次执行协议设置、目标CC线选择、稳定等待和VC查询 + Sink完整握手依次执行协议设置、目标CC线选择、稳定等待和VC查询 *****************************************************************/ static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW, rt_uint8_t *next_sub) @@ -815,6 +905,10 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx, (request_sub == IDX_SET_SINK_CCLINE)) { /* 北向Sink继电器保持接通,仅等待目标CC配置稳定。 */ chrg_roll_nor_sink_cc_wait_start(idx); + } else if ((expected_id == ID_SINK) && + (request_sub == IDX_SET_SINK_PD_ONLY)) { + /* 仅重发协议时没有CC回码作为节流入口,直接启动200ms计时。 */ + chrg_roll_nor_sink_query_wait_start(idx); } /* 业务解析可能主动切换sub,例如掉电恢复后要求重新设置协议。 * 只有sub仍属于本次请求时,才应用请求函数计算出的next_sub。 */ diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index fb9736a..8c94d0a 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -30,6 +30,27 @@ static rt_bool_t g_sink_unload_batch_confirmed[TOTAL_SOU_CHS] = {RT_FALSE}; static rt_tick_t g_sink_unload_query_tick[TOTAL_SOU_CHS] = {0}; static rt_uint8_t g_sink_unload_confirm_count[TOTAL_SOU_CHS] = {0}; +/***************************************************************** +函数名称: chrg_sink_load_should_start +函数描述: 判断普通负载的设定值是否允许启动南向电子负载 +输入参数: pSW:当前通道控制结构体 +输出参数: - +返回说明: RT_TRUE:允许WORK_START RT_FALSE:应保持WORK_STOP +其它说明: 门限只作用于恒流模式的负载电流loadc;协议电流pro_loadc无论 + 大小都继续参与北向握手,恒压模式不受该恒流门限限制 +*****************************************************************/ +rt_bool_t chrg_sink_load_should_start(const struct chrg_switch_t *pSW) +{ + if (pSW == RT_NULL) { + return RT_FALSE; + } + if (pSW->CV_mode != MODE_CONSTANT_CURRENT) { + return RT_TRUE; + } + return (pSW->sink.loadc >= SINK_LOAD_ENABLE_MIN_MA) ? + RT_TRUE : RT_FALSE; +} + /***************************************************************** 函数名称: chrg_sink_unload_confirm_reset 函数描述: 清除指定通道的卸载批次和低电流确认上下文 @@ -49,6 +70,24 @@ static void chrg_sink_unload_confirm_reset(eIDX_SOU_CH idx) g_sink_unload_confirm_count[idx] = 0U; } +/***************************************************************** +函数名称: chrg_sink_handshake_north_ready +函数描述: 判断完整握手的南向安全批次是否已经执行完成 +输入参数: idx:南向功率板通道 +输出参数: - +返回说明: RT_TRUE:辅助继电器命令已完成并已建立低电流量测基线 + RT_FALSE:南向安全批次仍在执行 +其它说明: 基线建立后返回成功,实际低电流确认仍由当前状态函数继续执行; + 用于允许北向协议/CC与南向低电流确认并行推进 +*****************************************************************/ +rt_bool_t chrg_sink_handshake_north_ready(eIDX_SOU_CH idx) +{ + if (idx >= TOTAL_SOU_CHS) { + return RT_FALSE; + } + return g_sink_unload_batch_confirmed[idx]; +} + /***************************************************************** 函数名称: chrg_sink_unload_query_submit 函数描述: 按最小间隔提交当前通道的一次性P1量测请求 @@ -188,66 +227,30 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf) /***************************************************************** 函数名称: chrg_sink_work_init -函数描述: 执行负载INIT入口,第一条南向命令只打开副继电器 +函数描述: 执行负载INIT入口,将副继电器和初始化命令按顺序提交南向 输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 禁止北向请求并进入SINK_WORK_INIT_AUX_WAIT -返回说明: 0:副继电器命令提交成功 <0:参数或命令提交失败 -其它说明: FU_REL_ON同时保证主继电器关闭;收到有效回码前不得启动北向握手 +输出参数: 立即打开北向Sink继电器和enable,并进入INIT_AUX_WAIT后台确认 +返回说明: 0:初始化批次提交成功 <0:参数或命令提交失败 +其它说明: 南向顺序为FU_REL_ON、CURRENT=0、MODE、VON和可选测试停止; + 北向协议握手不等待南向回码,南北向从批次入队后并行执行 *****************************************************************/ static int chrg_sink_work_init(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { struct chrg_north_t *pNOR = &chrgnorth; - rt_uint16_t reg = REG_REL_ON; - rt_uint16_t value = FU_REL_ON; + rt_uint16_t regs[5] = {REG_REL_ON, REG_CURRENT_OUT + 1, + REG_MODE, Eload_Start_V_ON, 0}; + rt_uint16_t vals[5] = {FU_REL_ON, 0, 0, 0, 0}; + rt_bool_t first_start; + rt_uint8_t count = 4U; if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return -1; } - if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { - return -1; - } - - /* 北向软件使能在副继电器回码后恢复,避免协议命令先于电压通路。 */ - pSW->sink.On_work = 1; - pNOR->enable[idx] = 0; - pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT; - return 0; -} - -/***************************************************************** -函数名称: chrg_sink_work_init_aux_wait -函数描述: 等待启动副继电器回码,并异步提交其余功率板初始化命令 -输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 打开北向Sink继电器、恢复北向使能并进入SINK_WORK_WAIT -返回说明: 0:继续等待或初始化命令已入队 <0:参数或命令提交失败 -其它说明: 其余初始化命令只要求成功入队,不等待执行完成;北向握手和 - 南向初始化可并行,后续RUNING命令追加到同一队列并保持顺序 -*****************************************************************/ -static int chrg_sink_work_init_aux_wait(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[4] = {REG_CURRENT_OUT + 1, REG_MODE, - Eload_Start_V_ON, 0}; - rt_uint16_t vals[4] = {0}; - rt_uint8_t count = 3U; - int batch_result; - - if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { - return -1; - } - vals[1] = pSW->CV_mode; - vals[2] = pSW->sink.volt_on; - if (chrg_sou_com_batch_is_pending(idx)) { - return 0; - } - batch_result = chrg_sou_com_batch_get_result(idx); - if (batch_result <= 0) { - /* 副继电器无有效回码时重新执行INIT,北向继续保持禁止。 */ - return chrg_sink_work_init(idx, pSW); - } - + /* COM进入INIT前已经设置On_work,使用原工作状态区分首次提交和后台重试。 */ + first_start = (pSW->sink.work_mode != SINK_WORK_INIT_AUX_WAIT) ? + RT_TRUE : RT_FALSE; + vals[2] = pSW->CV_mode; + vals[3] = pSW->sink.volt_on; if (pSW->sink.test.test_mode_old == SINK_TEST_SHORT) { regs[count] = ModbusRTU_ShortTest_CMD_MODE_FLAG; vals[count++] = ModbusRTU_DYNA_CMD_MODE_STOP; @@ -262,11 +265,45 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx, return -1; } - /* 初始化命令已按顺序入队,此时即可给协议板接通北向Sink路径。 */ + pSW->sink.On_work = 1; + if (first_start) { + /* 南向批次已入队,北向按“协议->CC”顺序立即开始完整握手。 */ + chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK); + pNOR->enable[idx] = 1; + pSW->sub = IDX_SET_SINK_PD; + } + pSW->sink.work_mode = SINK_WORK_INIT_AUX_WAIT; + return 0; +} + +/***************************************************************** +函数名称: chrg_sink_work_init_aux_wait +函数描述: 后台等待整组南向初始化命令完成,不阻塞北向协议握手 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 初始化完成后进入SINK_WORK_WAIT,失败时重提整个初始化批次 +返回说明: 0:继续等待或初始化完成 <0:参数错误 +其它说明: 重试时保留当前北向sub,禁止把正在执行的协议/CC事务拉回起点 +*****************************************************************/ +static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + struct chrg_south_t *pSOU = &chrgsouth; + int batch_result; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (chrg_sou_com_batch_is_pending(idx)) { + return 0; + } + batch_result = chrg_sou_com_batch_get_result(idx); + if (batch_result <= 0) { + /* 北向保持当前事务,南向独立重试完整初始化批次。 */ + return chrg_sink_work_init(idx, pSW); + } + + /* 北向可能已推进到CC或电压查询,此处只更新南向完成状态。 */ pSOU->online[idx] = 1; - pNOR->enable[idx] = 1; - chrg_nor_sw_rel((eIDX_NOR_CH)idx, ID_SINK); - pSW->sub = IDX_SET_SINK_PD; pSW->sink.test.test_mode_old = 0; pSW->sink.work_mode = SINK_WORK_WAIT; return 0; @@ -274,60 +311,173 @@ static int chrg_sink_work_init_aux_wait(eIDX_SOU_CH idx, /***************************************************************** 函数名称: chrg_sink_work_volt_runing -函数描述: 执行负载RUNING状态,闭合功率继电器并启动负载 +函数描述: 执行负载RUNING状态,闭合全部继电器并启动负载 输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 输出参数: - 返回说明: 0:命令提交成功 非0:命令提交失败 -其它说明: CV模式下写负载电压,其他模式下写负载电流;副继电器0x02 - 收到有效回码后直接发送全部继电器0x03,当前不增加固定延时 +其它说明: 辅助继电器已在INIT、重握手或掉电恢复阶段打开;RUNING只发送 + ALL_REL_ON、目标负载值和WORK_START,避免FU_REL_ON重复关闭主继电器 *****************************************************************/ static int chrg_sink_work_volt_runing(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { - rt_uint16_t regs[4] = {0x01, 0x01, 0, REG_WORK}; - rt_uint16_t vals[4] = {0x02, 0x03, 0, WORK_START}; - - if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { - regs[2] = REG_VOLTAGE_OUT + 1; - vals[2] = pSW->sink.loadv; - } else { - regs[2] = REG_CURRENT_OUT + 1; - vals[2] = pSW->sink.loadc; - } - return chrg_sou_com_batch_submit(idx, regs, vals, 4); -} - -/***************************************************************** -函数名称: chrg_sink_work_soft_resume -函数描述: 仅协议电压变化完成后恢复负载,不操作南向主副继电器 -输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 -输出参数: 命令入队成功后将工作状态切换为SINK_WORK_SOFT_RUNNING -返回说明: 0:命令提交成功 <0:参数或命令提交失败 -其它说明: 命令顺序为目标电流/电压、WORK_START,保证软卸载期间继电器 - 始终保持原状态,避免恢复阶段因FU_REL_ON造成主继电器短暂断开 -*****************************************************************/ -static int chrg_sink_work_soft_resume(eIDX_SOU_CH idx, - struct chrg_switch_t *pSW) -{ - rt_uint16_t regs[2] = {0, REG_WORK}; - rt_uint16_t vals[2] = {0, WORK_START}; + rt_uint16_t regs[3] = {REG_REL_ON, 0, REG_WORK}; + rt_uint16_t vals[3] = {ALL_REL_ON, 0, WORK_START}; + int ret; if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { return -1; } - if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { - regs[0] = REG_VOLTAGE_OUT + 1; - vals[0] = pSW->sink.loadv; - } else { - regs[0] = REG_CURRENT_OUT + 1; - vals[0] = pSW->sink.loadc; + if (!chrg_sink_load_should_start(pSW)) { + /* + * 北向协议已完成,低电流设定仍需要接通主继电器,使负载通路 + * 处于完整连接状态;但禁止电子负载带载,随后发送WORK_STOP并 + * 清零电流,避免0A或几十mA设定造成启动冲击。 + */ + rt_uint16_t stop_regs[3] = {REG_REL_ON, REG_WORK, + REG_CURRENT_OUT + 1}; + rt_uint16_t stop_vals[3] = {ALL_REL_ON, WORK_STOP, 0}; + + ret = chrg_sou_com_batch_submit(idx, stop_regs, stop_vals, 3U); + if (ret == 0) { + pSW->sink.work_mode = SINK_WORK_LOAD_STANDBY; + } + return ret; } - if (chrg_sou_com_batch_submit(idx, regs, vals, 2U) != 0) { + + if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { + regs[1] = REG_VOLTAGE_OUT + 1; + vals[1] = pSW->sink.loadv; + } else { + regs[1] = REG_CURRENT_OUT + 1; + vals[1] = pSW->sink.loadc; + } + return chrg_sou_com_batch_submit(idx, regs, vals, 3U); +} + +/***************************************************************** +函数名称: chrg_sink_work_soft_resume +函数描述: 协议电压或协议电流变化完成后恢复负载 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 命令入队成功后将工作状态切换为SINK_WORK_SOFT_RUNNING +返回说明: 0:命令提交成功 <0:参数或命令提交失败 +其它说明: 命令顺序为ALL_REL_ON、目标电流/电压、WORK_START;快速切换时 + 主继电器可能在完整握手阶段被关闭,恢复必须先确保继电器闭合 + 再启动电子负载,避免WORK_START先于主继电器带载;南向固件 + 继电器独立控制,ALL_REL_ON只开不关,不会误关已闭合的副继电器 +*****************************************************************/ +static int chrg_sink_work_soft_resume(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + rt_uint16_t regs[3] = {REG_REL_ON, 0, REG_WORK}; + rt_uint16_t vals[3] = {ALL_REL_ON, 0, WORK_START}; + int ret; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (!chrg_sink_load_should_start(pSW)) { + /* 软卸载未切继电器,低电流下继续保持原继电器和协议状态。 */ + regs[0] = REG_WORK; + vals[0] = WORK_STOP; + regs[1] = REG_CURRENT_OUT + 1; + vals[1] = 0; + ret = chrg_sou_com_batch_submit(idx, regs, vals, 2U); + if (ret == 0) { + pSW->sink.work_mode = SINK_WORK_LOAD_SOFT_STANDBY; + } + return ret; + } + if (pSW->CV_mode == MODE_CONSTANT_VOLTAGE) { + regs[1] = REG_VOLTAGE_OUT + 1; + vals[1] = pSW->sink.loadv; + } else { + regs[1] = REG_CURRENT_OUT + 1; + vals[1] = pSW->sink.loadc; + } + if (chrg_sou_com_batch_submit(idx, regs, vals, 3U) != 0) { return -1; } pSW->sink.work_mode = SINK_WORK_SOFT_RUNNING; return 0; } +/***************************************************************** +函数名称: chrg_sink_work_load_stop +函数描述: 普通负载运行中设定电流降到最低门限以下时安全停止带载 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 命令入队成功后进入SINK_WORK_LOAD_SOFT_STANDBY +返回说明: 0:命令提交成功 <0:参数或命令提交失败 +其它说明: 命令顺序固定为WORK_STOP、CURRENT=0;不改变北向协议、CC和 + 主副继电器,保证后续恢复有效电流时无需重新协议握手 +*****************************************************************/ +static int chrg_sink_work_load_stop(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + rt_uint16_t regs[2] = {REG_WORK, REG_CURRENT_OUT + 1}; + rt_uint16_t vals[2] = {WORK_STOP, 0}; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + if (chrg_sou_com_batch_submit(idx, regs, vals, 2U) != 0) { + return -1; + } + pSW->sink.work_mode = SINK_WORK_LOAD_SOFT_STANDBY; + return 0; +} + +/***************************************************************** +函数名称: chrg_sink_work_load_resume +函数描述: 从保持继电器的低电流待机状态恢复普通电子负载 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 命令入队成功后进入SINK_WORK_SOFT_RUNNING +返回说明: 0:命令提交成功 <0:参数或命令提交失败 +其它说明: 命令顺序为ALL_REL_ON、目标负载电流、WORK_START;不重新设置 + 协议或CC;低电流待机可能由软卸载进入且主继电器未闭合,恢复时 + 必须先把继电器打开再启动,防止电子负载先于主继电器带载 +*****************************************************************/ +static int chrg_sink_work_load_resume(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + rt_uint16_t regs[3] = {REG_REL_ON, REG_CURRENT_OUT + 1, REG_WORK}; + rt_uint16_t vals[3] = {ALL_REL_ON, 0, WORK_START}; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL) || + !chrg_sink_load_should_start(pSW)) { + return -1; + } + vals[1] = pSW->sink.loadc; + if (chrg_sou_com_batch_submit(idx, regs, vals, 3U) != 0) { + return -1; + } + pSW->sink.work_mode = SINK_WORK_SOFT_RUNNING; + return 0; +} + +/***************************************************************** +函数名称: chrg_sink_work_load_start +函数描述: 从主继电器未打开的低电流待机状态执行完整负载启动 +输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 +输出参数: 命令入队成功后进入SINK_WORK_RUNING +返回说明: 0:命令提交成功 <0:参数或命令提交失败 +其它说明: 使用独立入口避开状态机对RUNING的重复状态去重;执行副继电器、 + 全部继电器、目标负载值和WORK_START的标准启动顺序 +*****************************************************************/ +static int chrg_sink_work_load_start(eIDX_SOU_CH idx, + struct chrg_switch_t *pSW) +{ + int ret; + + if ((idx >= TOTAL_SOU_CHS) || (pSW == RT_NULL)) { + return -1; + } + ret = chrg_sink_work_volt_runing(idx, pSW); + if ((ret == 0) && (pSW->sink.work_mode == SINK_WORK_LOAD_START)) { + pSW->sink.work_mode = SINK_WORK_RUNING; + } + return ret; +} + /***************************************************************** 函数名称: chrg_sink_nor_work_low 函数描述: 执行负载掉电处理,卸载后关闭主副继电器并重新打开副继电器 @@ -397,8 +547,8 @@ static int chrg_sink_nor_work_off(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[2] = {0x01, REG_WORK}; - rt_uint16_t vals[2] = {0x00, WORK_STOP}; + rt_uint16_t regs[2] = {REG_REL_ON, REG_WORK}; + rt_uint16_t vals[2] = {ALL_REL_OFF, WORK_STOP}; if (chrg_sou_com_batch_submit(idx, regs, vals, 2) != 0) { return -1; @@ -442,7 +592,7 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) /* 停止成功入队后,清除旧Source运行标志。 */ pSW->source.On_Flag = 0; - /* 首次进入Sink时从协议配置开始,协议应答后再设置目标CC线。 */ + /* 首次进入Sink时先设置协议,协议应答后再设置目标CC线。 */ pSW->sub = IDX_SET_SINK_PD; /* SWITCH只负责旧角色退出,后续启动统一交给Sink INIT状态。 */ pSW->sink.work_mode = SINK_WORK_INIT; @@ -451,23 +601,23 @@ static int chrg_sink_work_switch(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) /***************************************************************** 函数名称: chrg_sink_work_protocol_unload -函数描述: 仅协议电压变化前的软卸载:停止负载并将设定电流归零 +函数描述: 协议电压或电流变化前的软卸载:停止电子负载 输入参数: idx:南向功率通道编号 pSW:当前通道控制结构体 输出参数: - 返回说明: 0:命令提交成功 <0:命令提交失败 -其它说明: 不操作北向和南向功率继电器;两条写命令完成后进入UNLOAD_WAIT, +其它说明: 不操作北向和南向功率继电器;WORK_STOP完成后进入UNLOAD_WAIT, 连续确认两帧实际电流不大于100mA,才允许北向重配协议并使用软恢复流程 *****************************************************************/ static int chrg_sink_work_protocol_unload(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) { - rt_uint16_t regs[2] = {REG_WORK, REG_CURRENT_OUT + 1}; - rt_uint16_t vals[2] = {WORK_STOP, 0}; + rt_uint16_t reg = REG_WORK; + rt_uint16_t value = WORK_STOP; - if (chrg_sou_com_batch_submit(idx, regs, vals, 2) != 0) { + if (chrg_sou_com_batch_submit(idx, ®, &value, 1U) != 0) { return -1; } - /* 写回码只确认命令接收;批次完成后还需连续读取两帧合格的实际电流。 */ + /* WORK_STOP回码只确认命令接收;还需连续读取两帧合格的实际电流。 */ chrg_sink_unload_confirm_reset(idx); pSW->sink.work_mode = SINK_WORK_UNLOAD_WAIT; return 0; @@ -510,11 +660,11 @@ static int chrg_sink_work_handshake_prepare(eIDX_SOU_CH idx, 函数名称: chrg_sink_work_current_wait 函数描述: 等待负载安全断开批次完成,并连续确认两帧实际电流不大于100mA 输入参数: idx:南向功率板通道 pSW:当前通道控制结构体 - full_handshake:RT_TRUE为完整重握手 RT_FALSE为仅协议电压软卸载 + full_handshake:RT_TRUE为完整重握手 RT_FALSE为协议参数软卸载 输出参数: 确认成功后将sink.work_mode切换为SINK_WORK_WAIT 返回说明: 0:继续等待或确认成功 <0:状态查询或优先量测请求失败 -其它说明: 只有WORK_STOP和CURRENT=0均收到匹配回码后才建立量测基线; - 完整重握手还要求ALL_REL_OFF和FU_REL_ON回码成功,但保持北向Sink继电器接通 +其它说明: 软卸载只要求WORK_STOP收到匹配回码后建立量测基线;完整重握手 + 还要求CURRENT=0、ALL_REL_OFF和FU_REL_ON回码成功,但保持北向Sink继电器接通 *****************************************************************/ static int chrg_sink_work_current_wait(eIDX_SOU_CH idx, struct chrg_switch_t *pSW, rt_bool_t full_handshake) @@ -736,6 +886,19 @@ int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW) case SINK_WORK_HANDSHAKE_WAIT: ret = chrg_sink_work_current_wait(idx, pSW, RT_TRUE); break; + case SINK_WORK_LOAD_STANDBY: + case SINK_WORK_LOAD_SOFT_STANDBY: + ret = 0; + break; + case SINK_WORK_LOAD_STOP: + ret = chrg_sink_work_load_stop(idx, pSW); + break; + case SINK_WORK_LOAD_START: + ret = chrg_sink_work_load_start(idx, pSW); + break; + case SINK_WORK_LOAD_RESUME: + ret = chrg_sink_work_load_resume(idx, pSW); + break; default: break; } diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index 89d75f4..270e396 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -201,6 +201,15 @@ enum { #define SINK_CMD_SET_AVS 0xE3 // AVS +/* + * 普通恒流负载允许执行WORK_START的最低设定电流,单位mA。 + * 小于该值时北向仍完成协议握手,但南向保持WORK_STOP且设定电流为0, + * 避免功率板在零电流或几十mA的小电流设定下启动电子负载产生冲击。 + */ +#define SINK_LOAD_ENABLE_MIN_MA 100U + +extern rt_bool_t chrg_sink_handshake_north_ready(eIDX_SOU_CH idx); + enum { SINK_WORK_INIT = 0, // 启动入口:第一条南向命令只打开副继电器 SINK_WORK_INIT_AUX_WAIT, // 等待启动副继电器收到有效南向回码 @@ -212,7 +221,7 @@ enum { SINK_WORK_LOW_MONITOR, // 副继电器已恢复,等待输入电压重新出现 SINK_WORK_STOP, // 用户主动停止负载 SINK_WORK_SWITCH, // 停止旧电源后进入负载INIT - SINK_WORK_PROTOCOL_UNLOAD, // 仅协议电压变化:掉载但不切换继电器 + SINK_WORK_PROTOCOL_UNLOAD, // 协议电压或电流变化:掉载但不切换继电器 SINK_WORK_UNLOAD_WAIT, // 等待软卸载完成并连续两次确认电流不大于100mA SINK_WORK_SOFT_RESUME_WAIT, // 继电器保持闭合,等待协议电压稳定后恢复负载 SINK_WORK_SOFT_RESUME, // 只恢复目标电流/电压和WORK_START,不写继电器 @@ -221,7 +230,12 @@ enum { SINK_WORK_ON_TEST_SHORT, // 短路测试启动状态 SINK_WORK_ON_TEST_OCP, // OCP过流保护测试启动状态 SINK_WORK_HANDSHAKE_PREPARE, // 完整重握手:停止、清流、全关继电器后打开副继电器 - SINK_WORK_HANDSHAKE_WAIT, // 等待完整重握手批次及连续两次低电流确认 + SINK_WORK_HANDSHAKE_WAIT, // 南向低电流确认与北向协议/CC并行 + SINK_WORK_LOAD_STANDBY, // 协议已就绪但主继电器未打开,低设定电流下保持停止 + SINK_WORK_LOAD_SOFT_STANDBY, // 协议和继电器保持不变,运行中降至低电流后的停止状态 + SINK_WORK_LOAD_STOP, // 运行中跨到低电流:发送WORK_STOP后将设定电流清零 + SINK_WORK_LOAD_START, // 主继电器未打开的低电流待机恢复:执行完整RUNING动作 + SINK_WORK_LOAD_RESUME, // 软待机跨回有效电流:不切继电器,直接恢复电流和WORK_START }; // sink 参数结构 @@ -393,6 +407,8 @@ extern void chrg_nor_sink_change_test(rt_uint8_t ch, struct chrg_switch_t *pSW); extern void chrg_nor_sink_test_stop(rt_uint8_t ch,struct chrg_switch_t *pSW,rt_uint8_t *enable); extern void chrg_nor_sink_test_run(rt_uint8_t ch, struct chrg_switch_t *pSW); +/* 判断普通负载的当前设定是否允许启动电子负载。 */ +extern rt_bool_t chrg_sink_load_should_start(const struct chrg_switch_t *pSW); extern int chrg_sink_work(eIDX_SOU_CH idx, struct chrg_switch_t *pSW); #endif diff --git a/apps/chrg/codex_build.log b/apps/chrg/codex_build.log index 405751e..5b5cbf5 100644 --- a/apps/chrg/codex_build.log +++ b/apps/chrg/codex_build.log @@ -1,20 +1,8 @@ *** Using Compiler 'V6.16', folder: 'D:\keil mdk 2\ARM\ARMCLANG\Bin' Build target 'chrg' -compiling chrg_north_pkg.c... -compiling chrg_lcd.c... -compiling chrg_thread.c... -compiling chrg_sink.c... -compiling chrg_vcom.c... -compiling chrg_rel.c... -compiling chrg_eload.c... -compiling chrg_south.c... -compiling chrg_roll_sou.c... -compiling chrg_north.c... -compiling chrg_source.c... compiling chrg_roll_nor.c... -compiling chrg_comm.c... linking... -Program Size: Code=145588 RO-data=15276 RW-data=9328 ZI-data=15944 +Program Size: Code=146668 RO-data=15332 RW-data=9328 ZI-data=15968 FromELF: creating hex file... After Build - User command #1: fromelf --bin .\build\keil\Obj\chrg.axf -o build/chrg.bin ".\build\keil\Obj\chrg.axf" - 0 Error(s), 0 Warning(s). diff --git a/docs/修改日志.md b/docs/修改日志.md index cc03c3c..e37bb6e 100644 --- a/docs/修改日志.md +++ b/docs/修改日志.md @@ -1,5 +1,167 @@ # 修改日志 +## V1.1.7 - 2026-08-08 + +### 修改主题 + +并行执行Sink完整握手中的南向低电流确认与北向协议/CC设置。 + +### 主要修改 + +- 南向安全批次完成并收到辅助继电器回码、建立量测基线后,立即允许北向设置协议和CC线。 +- 南向实际电流连续两次不大于 `100mA` 的确认过程与北向协议/CC设置并行执行。 +- 北向进入 `GET_SINK_VC` 后,只有低电流确认完成且CC后的 `200ms` 查询保护时间到期,才发送第一条 `0x20`。 +- 电压稳定后再发送 `ALL_REL_ON -> 目标电流 -> WORK_START`,防止协议协商期间提前带载。 + +### 涉及文件 + +- `apps/chrg/applications/thread/chrg_roll_nor.c` +- `apps/chrg/applications/utils/chrg_sink.c` +- `apps/chrg/applications/utils/chrg_sink.h` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +## V1.1.5 - 2026-08-08 + +### 修改主题 + +协议电压和协议电流变化统一采用软卸载重发协议流程。 + +### 主要修改 + +- 协议类型、CC线和协议组号变化仍进入完整握手并切换南向继电器。 +- 协议电压、协议电流单独变化或同时变化时,只发送 `WORK_STOP`,不关闭南向继电器。 +- 软卸载不再额外发送 `CURRENT=0`,仅通过实际电流连续两次不大于 `100mA`确认电子负载已停止。 +- 协议重新生效且电压稳定后,由RUNNING先写入实际负载电流,再发送 `WORK_START`。 + +### 涉及文件 + +- `apps/chrg/applications/thread/chrg_comm.c` +- `apps/chrg/applications/utils/chrg_sink.c` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +## V1.1.4 - 2026-08-07 + +### 修改主题 + +调整负载低电流启动时的继电器和工作命令顺序。 + +### 主要修改 + +- 设定电流为 `0A` 或低于 `100mA` 时,协议握手仍正常执行。 +- 电压达到目标后发送 `ALL_REL_ON`,确保主继电器打开。 +- 主继电器打开后继续发送 `WORK_STOP` 和 `CURRENT=0`,保持电子负载不带载。 +- 已经处于运行状态切换到低电流时,沿用原有停止流程,不重复切换继电器。 + +### 涉及文件 + +- `apps/chrg/applications/utils/chrg_sink.c` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +## V1.1.3 - 2026-08-07 + +### 修改主题 + +并行执行Sink南向初始化与北向握手,并优化握手查询和RUNING继电器时序。 + +### 主要修改 + +- `INIT`将 `FU_REL_ON -> CURRENT=0 -> MODE -> VON` 作为一个有序南向批次提交。 +- 南向初始化批次成功入队后立即打开北向Sink继电器、设置 `enable=1` 并开始协议握手。 +- `SINK_WORK_INIT_AUX_WAIT`改为后台监控南向初始化,不再阻塞北向协议、CC和电压查询。 +- 南向初始化失败重试时保留当前北向 `sub`,不重复拉回协议设置起点。 +- 协议或CC有效回码后,首条 `0x20` 等待 `200ms`;电压未稳定时后续每 `100ms` 查询一次。 +- 一帧通过CRC、ID、命令和配置版本校验的电压达到目标后立即进入 `RUNING`,不再等待第二帧。 +- 进入稳定运行后立即解除查询节流,恢复北向正常轮询速度。 +- `RUNING`删除重复的 `FU_REL_ON`,调整为 `ALL_REL_ON -> 目标负载值 -> WORK_START`。 + +### 涉及文件 + +- `apps/chrg/applications/utils/chrg_sink.c` +- `apps/chrg/applications/thread/chrg_roll_nor.c` +- `apps/chrg/applications/thread/chrg_north.c` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +### 硬件验证 + +- 待确认南向初始化命令与北向协议/CC设置并行执行且互不重置状态。 +- 待确认首条和后续 `0x20` 间隔分别约为 `200ms` 和 `100ms`。 +- 待确认进入 `RUNING` 时不再发送 `FU_REL_ON`,主继电器不会被重复断开。 + +## V1.1.2 - 2026-08-07 + +### 修改主题 + +降低Sink协议握手阶段的北向电压电流查询频率。 + +### 主要修改 + +- 新增 `SINK_HANDSHAKE_QUERY_INTERVAL_MS`,设置为 `200ms`。 +- Sink协议或CC设置收到有效回码后,不立即发送或连续快速发送 `0x20` 查询。 +- CC路径的 `200ms` 从有效 `0x17` 回码时刻开始计时,包含原有 `50ms` CC稳定保护。 +- 协议握手、软恢复等待和掉电恢复监控阶段的 `0x20` 查询按每 `200ms` 一次执行。 +- 北向量测连续两次达到稳定条件后解除节流,`RUNING` 和低电流待机恢复正常查询频率。 +- 仅重发协议的 `IDX_SET_SINK_PD_ONLY` 路径同样启动 `200ms` 查询等待。 +- 设置协议和CC命令仍然按有效回码、超时和原有重试机制处理。 + +### 涉及文件 + +- `apps/chrg/applications/thread/chrg_roll_nor.c` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +### 硬件验证 + +- 待观察协议/CC设置后 `0x20` 的发送间隔是否稳定为不小于 `200ms`。 +- 待验证电压连续两次稳定后是否恢复正常量测频率。 + +## V1.1.1 - 2026-08-07 + +### 修改主题 + +增加普通负载最低带载电流控制,低电流时保持协议在线但关闭电子负载。 + +### 主要修改 + +- 新增 `SINK_LOAD_ENABLE_MIN_MA`,恒流负载设定低于 `100mA` 时禁止发送 `WORK_START`。 +- 最低带载门限只判断南向负载电流 `loadc`,不影响北向协议电流 `pro_loadc` 和协议握手。 +- 首次启动或完整重握手后为低电流时,发送 `WORK_STOP -> CURRENT=0` 并保持主继电器关闭。 +- 运行中由有效电流降至低电流时,发送 `WORK_STOP -> CURRENT=0`,保持协议、CC和继电器不变。 +- 运行中低电流待机恢复有效电流时,只发送目标电流和 `WORK_START`,不重新握手或切换继电器。 +- 主继电器未打开的低电流待机使用独立 `SINK_WORK_LOAD_START` 恢复入口,避免被 `RUNING` 状态去重。 +- 低电流待机期间仅修改协议电压时不重复卸载,并保持原有主继电器状态语义。 +- 将 COM 端运行电流跨门限判断封装为 `chrg_comm_handle_sink_load_current()`,避免生效分支继续膨胀。 +- 北向解析将两种低电流待机状态作为稳定状态,不因实际电流为零反复进入 `RUNING`。 + +### 涉及文件 + +- `apps/chrg/applications/utils/chrg_sink.h` +- `apps/chrg/applications/utils/chrg_sink.c` +- `apps/chrg/applications/thread/chrg_comm.c` +- `apps/chrg/applications/thread/chrg_north.c` + +### 编译验证 + +- Keil MDK 编译结果:`0 Error(s), 0 Warning(s)`。 + +### 硬件验证 + +- 待验证 `20V/3A -> 20V/0A -> 20V/3A` 的南向命令顺序和协议保持情况。 +- 待验证首次以低于 `100mA` 的电流启动时,北向握手正常且南向不执行 `WORK_START`。 + ## V1.1.0 - 2026-08-07 ### 修改主题