修复了频繁切换电源PD协议会卡死的问题

refactor(chrg): 重构Source协议切换流程,替换CC断开为复位命令

1. 修改apps/chrg/applications/thread/chrg_north.c:新增SRC_CMD_RESET命令的帧长度校验
2. 修改apps/chrg/applications/thread/chrg_comm.h:新增chrg_comm_source_protocol_ack函数声明
3. 修改apps/chrg/applications/thread/chrg_north.h:开启北向UART调试打印
4. 修改apps/chrg/applications/utils/chrg_source.h:新增SRC_CMD_RESET命令码和source_reset函数声明
5. 修改apps/chrg/applications/thread/chrg_roll_nor.h:替换CC断开相关状态为复位状态
6. 修改apps/chrg/applications/utils/chrg_source.c:实现source_reset函数,修复PD参数硬编码问题
7. 修改apps/chrg/applications/thread/chrg_comm.c:新增协议状态缓存,重构协议切换判断逻辑
8. 修改apps/chrg/applications/thread/chrg_roll_nor.c:移除CC断开相关的共享等待逻辑,更新命令处理流程
This commit is contained in:
wrh
2026-08-22 16:55:25 +08:00
parent de45a902fe
commit 72cf1b75fa
8 changed files with 70 additions and 102 deletions
+34 -15
View File
@@ -55,6 +55,28 @@ static rt_tick_t g_ymodem_c_tick = 0;
static struct chrg_switch_t g_shadow_sw[TOTAL_NOR_CHS];
static rt_uint8_t g_shadow_dirty[TOTAL_NOR_CHS] = {0}; /* 0=已生效 1=待生效,防止重复覆盖 */
/* Source协议类别缓存:0xFF表示本通道尚未成功下发过协议。 */
#define SOURCE_PD_STATE_UNKNOWN 0xFFU
#define SOURCE_PD_STATE_NON_PD 0x00U
#define SOURCE_PD_STATE_PD 0x01U
static rt_uint8_t last_pd_pro[TOTAL_NOR_CHS] = {
SOURCE_PD_STATE_UNKNOWN, SOURCE_PD_STATE_UNKNOWN,
SOURCE_PD_STATE_UNKNOWN, SOURCE_PD_STATE_UNKNOWN
};
static rt_uint8_t chrg_comm_source_pd_state(rt_uint8_t protocol)
{
return ((protocol == PRO_PD0PSS) || (protocol == PRO_PD31AVS)) ?
SOURCE_PD_STATE_PD : SOURCE_PD_STATE_NON_PD;
}
void chrg_comm_source_protocol_ack(rt_uint8_t ch, rt_uint8_t protocol)
{
if (ch < TOTAL_NOR_CHS) {
last_pd_pro[ch] = chrg_comm_source_pd_state(protocol);
}
}
/*
* Source和Sink共用的参数差异结果。前五项是两个角色都具备的控制属性,
* pd_changed用于Source完整协议参数比较,后三项用于Sink快充协议配置。
@@ -2519,9 +2541,8 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
rt_bool_t cc_changed;
rt_bool_t north_config_changed;
rt_bool_t protocol_switch_requested;
rt_bool_t old_is_pd;
rt_bool_t new_is_pd;
rt_bool_t need_cc_close;
rt_bool_t need_source_reset;
rt_uint8_t new_pd_state;
struct vc_pd_t old_pd_set;
eSRC_PRO old_protocol = pReal->source.protocol;
rt_uint8_t old_cc_set = pReal->source.CC_Set;
@@ -2546,12 +2567,10 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
cc_changed = diff_info.cc_changed;
north_config_changed = protocol_config_changed || cc_changed;
protocol_switch_requested = north_config_changed;
old_is_pd = (old_protocol == PRO_PD0PSS) ||
(old_protocol == PRO_PD31AVS);
new_is_pd = (pShadow->source.protocol == PRO_PD0PSS) ||
(pShadow->source.protocol == PRO_PD31AVS);
need_cc_close = (new_is_pd && north_config_changed) ||
(old_is_pd && !new_is_pd && diff_info.protocol_changed);
new_pd_state = chrg_comm_source_pd_state(
(rt_uint8_t)pShadow->source.protocol);
need_source_reset = (last_pd_pro[ch] != SOURCE_PD_STATE_UNKNOWN) &&
(last_pd_pro[ch] != new_pd_state);
target_curr = pShadow->source.pd_set.mm.max_cur;
/* 影子区只拥有COM配置;北向解析产生的运行目标和回读数据继续由pReal持有。 */
@@ -2565,6 +2584,8 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
if (source_work == 0x01) {
if (pReal->source.On_Flag == 0) {
/* 每次重新启动的第一次协议下发不发送复位。 */
last_pd_pro[ch] = SOURCE_PD_STATE_UNKNOWN;
/*
* 停止状态启动不需要先断开CC,直接从设置协议开始;
* 收到0xD0应答并等待保护时间后,再连接目标CC。
@@ -2585,12 +2606,8 @@ static eMBException chrg_comm_apply_source_effect(rt_uint8_t ch,
*/
if (north_config_changed) {
chrg_roll_nor_source_switch_reset(ch);
if (need_cc_close) {
pReal->sub = IDX_SET_SOURCE_CC_CLOSE;
chrg_roll_nor_source_cc_close_register(ch);
} else {
pReal->sub = IDX_SET_SOURCE_PD;
}
pReal->sub = need_source_reset ?
IDX_SET_SOURCE_RESET : IDX_SET_SOURCE_PD;
}
pReal->source.work_mode = SOURCE_WORK_WAIT;
@@ -2709,6 +2726,8 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset,
chrg_roll_nor_source_switch_reset(ch);
rt_memcpy(pReal, pSW, sizeof(struct chrg_switch_t));
if (new_id == ID_SOURCE) {
/* 角色重新切到Source后,首个协议命令不需要复位。 */
last_pd_pro[ch] = SOURCE_PD_STATE_UNKNOWN;
pReal->source.work_mode = SOURCE_WORK_SWITCH;
switch_ret = chrg_source_work_state(ch, pReal);
} else {
@@ -19,6 +19,9 @@
#define MB_HANDLERS_MAX (16)
/* 北向Source协议设置成功后,通知COM保存本通道的PD/非PD类别。 */
extern void chrg_comm_source_protocol_ack(rt_uint8_t ch, rt_uint8_t protocol);
typedef enum {
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
MB_REG_WRITE /*!< Update register values. */
@@ -471,6 +471,7 @@ static rt_bool_t chrg_north_frame_shape_valid(eIDX_ID id,
if (id == ID_SOURCE) {
if ((command == SRC_CMD_SET_CC_LEVEL) ||
(command == SRC_CMD_SET_CC_CHOOSE) ||
(command == SRC_CMD_RESET) ||
(command == SRC_CMD_SET_PROTOCOL)) {
return (length == MIN_FRAME_LENGTH) ? RT_TRUE : RT_FALSE;
}
+1 -1
View File
@@ -22,7 +22,7 @@
#define LEN_FRAME_HEAD (4) // [帧长, 0x00, id, 命令]
#define MIN_FRAME_LENGTH (5) // 帧最短5字节
#define WORK_MIN_VOLT 3000 // 工作电压下限,单位mV
#define NORTH_FRAME_DEBUG 0x00 // 北向UART原始收发帧
#define NORTH_FRAME_DEBUG 0x01 // 北向UART原始收发帧
#define NORTH_SOURCE_DEBUG 0x00 // Source协议解析及组帧
#define NORTH_SINK_DEBUG 0x00 // Sink协议解析及组帧
#define SOUTH_FRAME_DEBUG 0x00 // 南向UART原始收发帧
+11 -79
View File
@@ -18,6 +18,7 @@
#include "chrg_source.h"
#include "chrg_roll_nor.h"
#include "chrg_roll_sou.h"
#include "chrg_comm.h"
#include "chrg_north.h"
#include "chrg_switch.h"
#include "chrg_utils.h"
@@ -31,8 +32,6 @@
#define NORTH_MEASURE_MAX_ATTEMPTS 1U // 0x20量测查询失败后直接留给下一轮轮询重发
#define NORTH_RETRY_INTERVAL_MS 5U // 相同请求两次发送之间的保护间隔
#define NORTH_POLL_INTERVAL_MS 10U // 一个通道事务结束后到下一通道的轮询间隔
#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_WAIT_MS 50U // Sink设置目标CC应答后的非阻塞保护时间
#define SINK_HANDSHAKE_FIRST_QUERY_DELAY_MS 50U // 协议/CC回码后首条0x20的等待时间
@@ -53,10 +52,6 @@ struct chrg_rollnor_t chrgrollnor = {
};
/* 所有参与CC_CLOSE的通道共享300ms屏障;协议等待仍按通道独立计时。 */
static rt_uint8_t g_source_cc_close_pending_mask = 0U;
static rt_uint8_t g_source_cc_close_acked_mask = 0U;
static rt_bool_t g_source_cc_close_wait_active = RT_FALSE;
static rt_tick_t g_source_cc_close_wait_start = 0U;
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;
@@ -114,25 +109,12 @@ static void chrg_roll_nor_sink_query_wait_start(rt_uint8_t ch)
*****************************************************************/
void chrg_roll_nor_source_switch_reset(rt_uint8_t ch)
{
rt_uint8_t bit;
if (ch >= TOTAL_NOR_CHS) {
return;
}
bit = SOURCE_CHANNEL_BIT(ch);
g_source_cc_close_pending_mask &= (rt_uint8_t)~bit;
g_source_cc_close_acked_mask &= (rt_uint8_t)~bit;
g_source_protocol_wait_mask &= (rt_uint8_t)~bit;
g_source_protocol_wait_mask &=
(rt_uint8_t)~SOURCE_CHANNEL_BIT(ch);
g_source_protocol_wait_start[ch] = 0U;
if (g_source_cc_close_pending_mask == 0U) {
g_source_cc_close_wait_active = RT_FALSE;
g_source_cc_close_wait_start = 0U;
} else if (!g_source_cc_close_wait_active &&
((g_source_cc_close_acked_mask & g_source_cc_close_pending_mask) ==
g_source_cc_close_pending_mask)) {
g_source_cc_close_wait_active = RT_TRUE;
g_source_cc_close_wait_start = rt_tick_get();
}
}
/*****************************************************************
@@ -143,41 +125,6 @@ void chrg_roll_nor_source_switch_reset(rt_uint8_t ch)
返回说明: -
其它说明: 新通道加入已经开始的屏障时重新等待,保证所有登记通道共享完整保护时间
*****************************************************************/
void chrg_roll_nor_source_cc_close_register(rt_uint8_t ch)
{
rt_uint8_t bit;
if (ch >= TOTAL_NOR_CHS) {
return;
}
bit = SOURCE_CHANNEL_BIT(ch);
g_source_cc_close_pending_mask |= bit;
g_source_cc_close_acked_mask &= (rt_uint8_t)~bit;
g_source_protocol_wait_mask &= (rt_uint8_t)~bit;
g_source_cc_close_wait_active = RT_FALSE;
g_source_cc_close_wait_start = 0U;
}
static void chrg_roll_nor_source_cc_close_ack(rt_uint8_t ch)
{
rt_uint8_t bit;
if (ch >= TOTAL_NOR_CHS) {
return;
}
bit = SOURCE_CHANNEL_BIT(ch);
if ((g_source_cc_close_pending_mask & bit) == 0U) {
return;
}
g_source_cc_close_acked_mask |= bit;
if (!g_source_cc_close_wait_active &&
((g_source_cc_close_acked_mask & g_source_cc_close_pending_mask) ==
g_source_cc_close_pending_mask)) {
g_source_cc_close_wait_active = RT_TRUE;
g_source_cc_close_wait_start = rt_tick_get();
}
}
static void chrg_roll_nor_source_protocol_wait_start(rt_uint8_t ch)
{
if (ch >= TOTAL_NOR_CHS) {
@@ -211,23 +158,6 @@ static rt_bool_t chrg_roll_nor_source_wait_process(rt_uint8_t ch,
return RT_FALSE;
}
if (pSW->sub == IDX_WAIT_SOURCE_CC_CLOSE) {
if ((g_source_cc_close_pending_mask & bit) == 0U) {
pSW->sub = IDX_SET_SOURCE_PD;
return RT_FALSE;
}
if (!g_source_cc_close_wait_active) {
return RT_TRUE;
}
elapsed = (rt_tick_t)(rt_tick_get() - g_source_cc_close_wait_start);
if (elapsed < rt_tick_from_millisecond(SOURCE_CC_CLOSE_WAIT_MS)) {
return RT_TRUE;
}
chrg_roll_nor_source_switch_reset(ch);
pSW->sub = IDX_SET_SOURCE_PD;
return RT_FALSE;
}
if (pSW->sub == IDX_WAIT_SOURCE_PROTOCOL) {
if ((g_source_protocol_wait_mask & bit) == 0U) {
pSW->sub = IDX_SET_SOURCE_CC_SET;
@@ -592,7 +522,8 @@ static rt_uint8_t chrg_roll_nor_expected_cmd(const struct chrg_switch_t *pSW)
return SRC_CMD_GET_PROTOCOL;
case IDX_SET_SOURCE_PD:
return SRC_CMD_SET_PROTOCOL;
case IDX_SET_SOURCE_CC_CLOSE:
case IDX_SET_SOURCE_RESET:
return SRC_CMD_RESET;
case IDX_SET_SOURCE_CC_SET:
return SRC_CMD_SET_CC_CHOOSE;
case IDX_SET_SOURCE_CCLVL:
@@ -793,9 +724,9 @@ static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW,
if(pSW->id==ID_SOURCE){ //电源
chrg_roll_nor_sw_uart((eIDX_NOR_CH)ch, ID_SOURCE);
switch(pSW->sub){
case IDX_SET_SOURCE_CC_CLOSE:
*next_sub = IDX_WAIT_SOURCE_CC_CLOSE;
return source_set_cc_choose(SOURCE_CC_CLOSE_VALUE);
case IDX_SET_SOURCE_RESET:
*next_sub = IDX_SET_SOURCE_PD;
return source_reset();
case IDX_SET_SOURCE_PD:
*next_sub = IDX_WAIT_SOURCE_PROTOCOL;
return chrg_roll_nor_source_pro_set(pSW);
@@ -936,13 +867,14 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx,
}
/* ID、命令、CRC和配置版本均确认有效后,才正式推进实时sub。 */
if ((expected_id == ID_SOURCE) &&
(request_sub == IDX_SET_SOURCE_CC_CLOSE)) {
(request_sub == IDX_SET_SOURCE_RESET)) {
/* 参与通道全部收到0x17=3应答后,共享一次300ms保护等待。 */
chrg_roll_nor_source_cc_close_ack(idx);
} else if ((expected_id == ID_SOURCE) &&
(request_sub == IDX_SET_SOURCE_PD)) {
/* 0xD0应答后每通道独立等待100ms,再连接目标CC。 */
chrg_roll_nor_source_protocol_wait_start(idx);
chrg_comm_source_protocol_ack(idx,
(rt_uint8_t)pSW->source.protocol);
} else if ((expected_id == ID_SINK) &&
((request_sub == IDX_SET_SINK_CCLINE) ||
(request_sub == IDX_SET_SINK_CC_BEFORE_PD))) {
@@ -43,8 +43,7 @@ enum {
IDX_SET_SINK_STORP_WAIT,
/* Source北向事务状态,追加在末尾以保持原有sub数值不变。 */
IDX_SET_SOURCE_CC_CLOSE, // 协议切换前发送0x17=0x03断开CC
IDX_WAIT_SOURCE_CC_CLOSE, // 等待参与切换的Source通道完成共享保护时间
IDX_SET_SOURCE_RESET, // PD与非PD协议跨类切换前发送Source复位
IDX_WAIT_SOURCE_PROTOCOL, // 0xD0应答后的协议生效等待
/* Sink北向事务状态追加在末尾,避免改变已有sub数值。 */
@@ -105,8 +104,6 @@ extern void roll_nor_set(void);
返回说明: -
其它说明: 仅需要在协议切换入口为IDX_SET_SOURCE_CC_CLOSE时调用
*****************************************************************/
extern void chrg_roll_nor_source_cc_close_register(rt_uint8_t ch);
/*****************************************************************
函数名称: chrg_roll_nor_source_switch_reset
函数描述: 清理指定Source通道的CC_CLOSE及协议等待记录
+15 -3
View File
@@ -148,7 +148,7 @@ static int chrg_source_work_protocol_switch(eIDX_SOU_CH idx,
int ret;
if ((pSW->sub != IDX_SET_SOURCE_PD) &&
(pSW->sub != IDX_SET_SOURCE_CC_CLOSE)) {
(pSW->sub != IDX_SET_SOURCE_RESET)) {
return -1;
}
@@ -316,6 +316,18 @@ int source_get_pd (void)
return chrg_north_send(frame, len);
}
int source_reset (void)
{
rt_uint16_t len = 0;
rt_uint8_t data[8] = {0};
rt_uint8_t frame[16] = {0};
data[0] = 0x00;
chrg_north_pkg_encode(ID_SOURCE, SRC_CMD_RESET, data, 1, frame, &len);
return chrg_north_send(frame, len);
}
/*****************************************************************
函数名称: source_set_cc_lvl
函数描述: source 设置 cc 等级
@@ -1017,8 +1029,8 @@ rt_uint8_t pd_fill_single_group_no_src_com(rt_uint8_t *data, rt_uint8_t start_id
data[idx++] = 0x00;
data[idx++] = 0x00;
// 2. 最小电压(高+低,直接取已拆分好的值)
data[idx++] = mm->min_vol >> 8;
data[idx++] = mm->min_vol & 0xFF;
data[idx++] = 0x13;//mm->min_vol >> 8;
data[idx++] = 0x18;//mm->min_vol & 0xFF;
// 3. 最大电压(高+低,直接取已拆分好的值)
data[idx++] = mm->max_vol >> 8;
data[idx++] = mm->max_vol & 0xFF;
@@ -25,6 +25,8 @@ struct chrg_switch_t;
#define SRC_CMD_SET_CC_CHOOSE 0x17
#define SRC_CMD_RESET 0x18
#define SRC_CMD_SET_PROTOCOL 0xD0
#define PROTOCOL_NONE 0x00 // 无快充
@@ -192,6 +194,8 @@ extern int source_get_vc (rt_uint16_t vol, rt_uint16_t cur);
*****************************************************************/
extern int source_get_pd (void);
extern int source_reset (void);
/*****************************************************************
函数名称: source_set_cc_lvl
函数描述: source 设置 cc 等级