diff --git a/apps/chrg/applications/thread/chrg_comm.c b/apps/chrg/applications/thread/chrg_comm.c index c229dcf..d442c1f 100644 --- a/apps/chrg/applications/thread/chrg_comm.c +++ b/apps/chrg/applications/thread/chrg_comm.c @@ -27,7 +27,7 @@ #include "stm32f4xx_hal.h" #define HOLD_REG_FIRMWARE_VERSION 0x0300U /* 协议板固件版本,只读 */ -#define CHRG_FIRMWARE_VERSION 0x0147U /* 当前协议板版本:V1.1.55 */ +#define CHRG_FIRMWARE_VERSION 0x0148U /* 当前协议板版本:V1.1.56 */ rt_uint8_t ucDiscInBuf[(TOTAL_DISC_REGS+BITS_UCHAR-1)/BITS_UCHAR]; @@ -1735,6 +1735,18 @@ static void chrg_mb_write_sink(rt_uint8_t ch, rt_uint16_t reg_offset, rt_uint16_ case SINK_REG_DYNA_UNLOAD: // 0x1E: 卸载斜率 pSW->sink.test.change_test.k_Fall = sou_value; break; + case SINK_REG_DPDM_DZ_K: // D+ K,实际比例系数放大10000倍 + pSW->sink.dpdm_cal.dz_k = sou_value; + break; + case SINK_REG_DPDM_DZ_B: // D+ B,单位0.01V,有符号16位 + pSW->sink.dpdm_cal.dz_b = (rt_int16_t)sou_value; + break; + case SINK_REG_DPDM_DF_K: // D- K,实际比例系数放大10000倍 + pSW->sink.dpdm_cal.df_k = sou_value; + break; + case SINK_REG_DPDM_DF_B: // D- B,单位0.01V,有符号16位 + pSW->sink.dpdm_cal.df_b = (rt_int16_t)sou_value; + break; default: rt_kprintf("[SINK CH%d] Unknown reg offset=0x%02X\n", ch + 1, reg_offset); break; @@ -1868,6 +1880,16 @@ static rt_bool_t chrg_comm_sink_config_equal(const struct chrg_switch_t *a, sizeof(a->sink.test.change_test)) == 0); } +/* D+/D-校准参数为独立北向事务,不并入普通负载状态机配置比较。 */ +static rt_bool_t chrg_comm_sink_dpdm_cal_equal(const struct chrg_switch_t *a, + const struct chrg_switch_t *b) +{ + return (a->sink.dpdm_cal.dz_k == b->sink.dpdm_cal.dz_k) && + (a->sink.dpdm_cal.dz_b == b->sink.dpdm_cal.dz_b) && + (a->sink.dpdm_cal.df_k == b->sink.dpdm_cal.df_k) && + (a->sink.dpdm_cal.df_b == b->sink.dpdm_cal.df_b); +} + /***************************************************************** 函数名称: chrg_comm_copy_sink_config 函数描述: 将PC配置逐项应用到Sink,保留实际运行状态、旧测试模式和量测 @@ -2373,6 +2395,27 @@ static eMBException chrg_mb_write_sys(rt_uint8_t ch, rt_uint16_t reg_offset, } status = (switch_ret == 0) ? MB_EX_NONE : MB_EX_SLAVE_BUSY; } else if (new_id == ID_SINK) { + /* + * D+/D-校准参数不是负载工作参数:上位机依次写入四个保持寄存器后, + * 必须单独写PARAM_EFFECT提交。若同时改了协议、CC或带载参数, + * 本次拒绝提交,避免校准写入抢占正在进行的负载状态机。 + */ + if (!chrg_comm_sink_dpdm_cal_equal(pReal, pSW)) { + if (!chrg_comm_sink_config_equal(pReal, pSW)) { + status = MB_EX_SLAVE_BUSY; + } else if (chrg_roll_nor_sink_dpdm_cal_submit(ch, pReal, + &pSW->sink.dpdm_cal) != 0) { + status = MB_EX_SLAVE_BUSY; + } else { + pNOR->config_version[ch]++; + status = MB_EX_NONE; + } + if (status != MB_EX_NONE) { + g_shadow_dirty[ch] = 1; + } + rt_mutex_release(pTHR_NOR->mutex); + return status; + } sink_config_changed = !chrg_comm_sink_config_equal(pReal, pSW); old_sink_sub = pReal->sub; old_sink_on = pReal->sink.On_work; diff --git a/apps/chrg/applications/thread/chrg_north.c b/apps/chrg/applications/thread/chrg_north.c index 9cf20ed..a8389b7 100644 --- a/apps/chrg/applications/thread/chrg_north.c +++ b/apps/chrg/applications/thread/chrg_north.c @@ -429,6 +429,7 @@ static rt_bool_t chrg_north_frame_shape_valid(eIDX_ID id, if (id == ID_SINK) { switch (command) { case SINK_CMD_RESET: + case SINK_CMD_SET_DPDM_CAL: case SINK_CMD_SET_CC: case SINK_CMD_SET_LEVEL: case SINK_CMD_SET_QC20: @@ -445,7 +446,9 @@ static rt_bool_t chrg_north_frame_shape_valid(eIDX_ID id, case SINK_CMD_SET_VOOC: case SINK_CMD_SET_AVS: case LOAD_PRO_NONE: - return (length == MIN_FRAME_LENGTH) ? RT_TRUE : RT_FALSE; + return (command == SINK_CMD_SET_DPDM_CAL) ? + ((length == 6U) ? RT_TRUE : RT_FALSE) : + ((length == MIN_FRAME_LENGTH) ? RT_TRUE : RT_FALSE); default: return RT_FALSE; } diff --git a/apps/chrg/applications/thread/chrg_north.h b/apps/chrg/applications/thread/chrg_north.h index 619eabf..e505e3c 100644 --- a/apps/chrg/applications/thread/chrg_north.h +++ b/apps/chrg/applications/thread/chrg_north.h @@ -16,7 +16,7 @@ #include "chrg_def.h" /* V_On启停判定电压源:切换后需重新编译固件。 */ -#define SINK_VON_VOLTAGE_FROM_PROTOCOL 6U +#define SINK_VON_VOLTAGE_FROM_PROTOCOL 1U #define SINK_VON_VOLTAGE_FROM_POWER 2U #ifndef SINK_VON_VOLTAGE_SOURCE #define SINK_VON_VOLTAGE_SOURCE SINK_VON_VOLTAGE_FROM_POWER diff --git a/apps/chrg/applications/thread/chrg_roll_nor.c b/apps/chrg/applications/thread/chrg_roll_nor.c index 9fbcd43..d0452bd 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.c +++ b/apps/chrg/applications/thread/chrg_roll_nor.c @@ -61,6 +61,17 @@ static rt_uint8_t g_sink_reset_next_sub[TOTAL_NOR_CHS] = {0}; /* 仅CC参数实际变化的通道才会断开D+/D-/CC,并在CC稳定后恢复。 */ static rt_uint8_t g_sink_cc_relay_close_mask = 0U; static rt_uint8_t g_sink_cc_relay_restore_mask = 0U; +/* D+/D-校准写入任务按通道独立保存,避免与普通0x20轮询共用参数缓存。 */ +struct sink_dpdm_cal_job_t { + struct sink_dpdm_cal_t cal; + rt_bool_t pending; + rt_uint8_t status; +}; +#define SINK_DPDM_CAL_STATUS_IDLE 0U +#define SINK_DPDM_CAL_STATUS_PENDING 1U +#define SINK_DPDM_CAL_STATUS_SUCCESS 2U +#define SINK_DPDM_CAL_STATUS_TIMEOUT 0x80U +static struct sink_dpdm_cal_job_t g_sink_dpdm_cal_job[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}; @@ -144,6 +155,29 @@ void chrg_roll_nor_sink_reset_cancel(rt_uint8_t ch) g_sink_cc_relay_restore_mask &= (rt_uint8_t)~SOURCE_CHANNEL_BIT(ch); } +rt_bool_t chrg_roll_nor_sink_dpdm_cal_pending(rt_uint8_t ch) +{ + return (ch < TOTAL_NOR_CHS) && g_sink_dpdm_cal_job[ch].pending; +} + +int chrg_roll_nor_sink_dpdm_cal_submit(rt_uint8_t ch, + struct chrg_switch_t *pSW, const struct sink_dpdm_cal_t *pCal) +{ + if ((ch >= TOTAL_NOR_CHS) || (pSW == RT_NULL) || (pCal == RT_NULL)) { + return -1; + } + /* 校准写入只抢占普通量测,不能覆盖初始化、协议/CC切换等事务。 */ + if (g_sink_dpdm_cal_job[ch].pending || (pSW->id != ID_SINK) || + (pSW->sub != IDX_GET_SINK_VC)) { + return -2; + } + g_sink_dpdm_cal_job[ch].cal = *pCal; + g_sink_dpdm_cal_job[ch].pending = RT_TRUE; + g_sink_dpdm_cal_job[ch].status = SINK_DPDM_CAL_STATUS_PENDING; + pSW->sub = IDX_SET_SINK_DPDM_CAL; + return 0; +} + void chrg_roll_nor_sink_cc_switch_prepare(rt_uint8_t ch, rt_bool_t cc_changed) { @@ -686,6 +720,8 @@ static rt_uint8_t chrg_roll_nor_expected_cmd(const struct chrg_switch_t *pSW) return SINK_CMD_SET_CC; case IDX_SET_SINK_CCLVL: return SINK_CMD_SET_LEVEL; + case IDX_SET_SINK_DPDM_CAL: + return SINK_CMD_SET_DPDM_CAL; default: return 0; } @@ -729,8 +765,12 @@ static int chrg_roll_nor_response_matches(const struct mb_msg_t *pMB, if ((expected_cmd == SRC_CMD_GET_VOLTAGE) && (pMB->length != 21U)) { return -3; } + if ((expected_cmd == SINK_CMD_SET_DPDM_CAL) && (pMB->length != 6U)) { + return -4; + } if ((expected_cmd != SRC_CMD_GET_VOLTAGE) && (expected_cmd != SRC_CMD_GET_PROTOCOL) && + (expected_cmd != SINK_CMD_SET_DPDM_CAL) && (pMB->length != MIN_FRAME_LENGTH)) { return -4; } @@ -910,6 +950,11 @@ static int chrg_roll_nor_set(rt_uint8_t ch, struct chrg_switch_t *pSW, return sink_set_cc_line(pSW->sink.cc_set); case IDX_SET_SINK_CCLVL: //CC电平 return sink_set_cc_lvl(pSW->sink.cc_lvl); + case IDX_SET_SINK_DPDM_CAL: + if (!g_sink_dpdm_cal_job[ch].pending) { + return -1; + } + return sink_set_dpdm_cal(&g_sink_dpdm_cal_job[ch].cal); case IDX_SET_SINK_PD: /* 只有协议回码确认后,下一轮才允许进入电压查询。 */ *next_sub = IDX_WAIT_SINK_PD_ACK; @@ -1030,6 +1075,26 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx, g_sink_reset_next_sub[idx] = 0U; advance_sub = RT_FALSE; } + } else if ((expected_id == ID_SINK) && + (request_sub == IDX_SET_SINK_DPDM_CAL)) { + /* + * 0x32回码格式:06 NC ID 32 STATUS CRC。 + * 只有STATUS为0才把任务参数提交到实时结构;否则保留原参数, + * 并回到0x20普通量测状态,避免失败写入影响负载流程。 + */ + g_sink_dpdm_cal_job[idx].pending = RT_FALSE; + g_sink_dpdm_cal_job[idx].status = pMB->payload[4]; + pSW->sub = IDX_GET_SINK_VC; + advance_sub = RT_FALSE; + if (pMB->payload[4] == 0U) { + pSW->sink.dpdm_cal = g_sink_dpdm_cal_job[idx].cal; + g_sink_dpdm_cal_job[idx].status = + SINK_DPDM_CAL_STATUS_SUCCESS; + LOG_I("sink dpdm cal write success: ch=%d", idx + 1U); + } else { + LOG_E("sink dpdm cal write failed: ch=%d status=%u", + idx + 1U, pMB->payload[4]); + } } else if ((expected_id == ID_SINK) && ((request_sub == IDX_SET_SINK_CCLINE) || (request_sub == IDX_SET_SINK_CC_BEFORE_PD) || @@ -1053,6 +1118,16 @@ static int chrg_roll_nor_auto_request(rt_uint8_t idx, LOG_W("north request failed: ch=%d id=%02x cmd=%02x sub=%d attempts=%d", idx + 1U, expected_id, expected_cmd, request_sub, max_attempts); + if ((expected_id == ID_SINK) && + (request_sub == IDX_SET_SINK_DPDM_CAL)) { + rt_mutex_take(pTHR->mutex, RT_WAITING_FOREVER); + g_sink_dpdm_cal_job[idx].pending = RT_FALSE; + g_sink_dpdm_cal_job[idx].status = SINK_DPDM_CAL_STATUS_TIMEOUT; + if (pSW->sub == IDX_SET_SINK_DPDM_CAL) { + pSW->sub = IDX_GET_SINK_VC; + } + rt_mutex_release(pTHR->mutex); + } return -1; } @@ -1152,6 +1227,18 @@ void chrg_roll_nor_thread_entry (void *data) rt_thread_mdelay(2); continue; } + /* 校准写入任务不依赖通道运行使能,优先占用一次北向事务。 */ + if (chrg_roll_nor_sink_dpdm_cal_pending(idx)) { + if ((chrg_north_switch((eIDX_NOR_CH)idx) == 0) && + (chrg_north_request_begin((eIDX_NOR_CH)idx) != 0U)) { + pROLL->idx = idx; + (void)chrg_roll_nor_auto_request(idx, pSW, + pTHR, pTN, pNOR); + } + CHRG_CHANNEL_NEXT(index); + rt_thread_mdelay(NORTH_POLL_INTERVAL_MS); + continue; + } if (source_waiting || sink_waiting) { CHRG_CHANNEL_NEXT(index); rt_thread_mdelay(2); diff --git a/apps/chrg/applications/thread/chrg_roll_nor.h b/apps/chrg/applications/thread/chrg_roll_nor.h index 75ad32e..cf197ba 100644 --- a/apps/chrg/applications/thread/chrg_roll_nor.h +++ b/apps/chrg/applications/thread/chrg_roll_nor.h @@ -11,6 +11,9 @@ #include +struct chrg_switch_t; +struct sink_dpdm_cal_t; + #define THR_NAME_ROLL_NOR "thr.rollnor" #define STATE_WORKING 0x03//运行标志位 enum { @@ -41,7 +44,8 @@ enum { IDX_SET_SINK_CC_BEFORE_PD_WITH_MODE, IDX_WAIT_SINK_CC_BEFORE_PD_WITH_MODE, IDX_SET_SINK_MODE_AFTER_PD, - IDX_WAIT_SINK_MODE_AFTER_PD + IDX_WAIT_SINK_MODE_AFTER_PD, + IDX_SET_SINK_DPDM_CAL // 上位机校准参数写入Sink板0x32 }; struct chrg_rollnor_t { @@ -112,6 +116,12 @@ extern void chrg_roll_nor_sink_cc_switch_prepare(rt_uint8_t ch, /* 低电流确认完成后,按登记结果断开D+/D-/CC继电器。 */ extern void chrg_roll_nor_sink_cc_relay_close(rt_uint8_t ch); +/* 提交Sink板D+/D-校准参数写入任务;仅空闲量测状态允许提交。 */ +extern int chrg_roll_nor_sink_dpdm_cal_submit(rt_uint8_t ch, + struct chrg_switch_t *pSW, const struct sink_dpdm_cal_t *pCal); +/* 查询指定通道是否存在待执行的D+/D-校准写入任务。 */ +extern rt_bool_t chrg_roll_nor_sink_dpdm_cal_pending(rt_uint8_t ch); + #define sink_time 3 #endif diff --git a/apps/chrg/applications/utils/chrg_def.h b/apps/chrg/applications/utils/chrg_def.h index f47ea70..61ca267 100644 --- a/apps/chrg/applications/utils/chrg_def.h +++ b/apps/chrg/applications/utils/chrg_def.h @@ -14,8 +14,7 @@ /* CHRG application version. Keep this value synchronized with the changelog. */ #define CHRG_VERSION_MAJOR 1U #define CHRG_VERSION_MINOR 1U -#define CHRG_VERSION_PATCH 55U -#define CHRG_VERSION_STRING "V1.1.55" + /* * Channel polling mode: diff --git a/apps/chrg/applications/utils/chrg_regs.h b/apps/chrg/applications/utils/chrg_regs.h index c18391e..8456f72 100644 --- a/apps/chrg/applications/utils/chrg_regs.h +++ b/apps/chrg/applications/utils/chrg_regs.h @@ -152,6 +152,12 @@ enum { #define SINK_REG_DYNA_TIME2 0x1C // ¸ºÔØ2±£³Öʱ¼ä (0.01ms) #define SINK_REG_DYNA_SLOPE 0x1D // ¶¯̬¼ÓÔØбÂÊ (0.001A/us) #define SINK_REG_DYNA_UNLOAD 0x1E // ¶¯̬жÔØбÂÊ (0.001A/us) +/* D+/D-У׼²ÎÊý£ºKΪÎ޷ûºÅ16루ʵ¼ʱÈÀýϵÊý¡Á10000£©£¬BΪÓзûºÅ16루0.01V£©¡£ + * ÉÏλ»úдÍêËÄÏîºó£¬д±¾ͨµÀSYS_REG_PARAM_EFFECT=1£¬ÓÉ405ת·¢Sink 0x32¡£ */ +#define SINK_REG_DPDM_DZ_K 0x1F // D+ K +#define SINK_REG_DPDM_DZ_B 0x20 // D+ B +#define SINK_REG_DPDM_DF_K 0x21 // D- K +#define SINK_REG_DPDM_DF_B 0x22 // D- B // ---- µçԴ(Source)²ÎÊýƫÒÆ (Ïà¶ÔͨµÀ»ùµØַ: HOLD_REG_SRC_BASE + ch*6) ---- #define SRC_REG_PROTOCOL 0x00 // ЭÒéÀàÐÍ diff --git a/apps/chrg/applications/utils/chrg_sink.c b/apps/chrg/applications/utils/chrg_sink.c index a9c6c17..610dfbd 100644 --- a/apps/chrg/applications/utils/chrg_sink.c +++ b/apps/chrg/applications/utils/chrg_sink.c @@ -302,6 +302,33 @@ int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf) return chrg_north_send(frame, len); } +/***************************************************************** +函数名称: sink_set_dpdm_cal +函数描述: 向Sink协议板写入D+/D-校准参数 +输入参数: pCal:四个16位校准参数 +输出参数: - +返回说明: <0:发送失败 >0:发送长度 +其它说明: 所有字段按高字节在前发送;B按int16_t补码原样发送 +*****************************************************************/ +int sink_set_dpdm_cal(const struct sink_dpdm_cal_t *pCal) +{ + rt_uint16_t len = 0U; + rt_uint8_t data[8] = {0}; + rt_uint8_t frame[16] = {0}; + + if (pCal == RT_NULL) { + return -1; + } + u16_to_u8v(pCal->dz_k, &data[0]); + u16_to_u8v((rt_uint16_t)pCal->dz_b, &data[2]); + u16_to_u8v(pCal->df_k, &data[4]); + u16_to_u8v((rt_uint16_t)pCal->df_b, &data[6]); + /* 发送帧:0D NC 01 32 DZ_K DZ_B DF_K DF_B CRC,四个16位字段均为大端。 */ + chrg_north_pkg_encode(ID_SINK, SINK_CMD_SET_DPDM_CAL, + data, sizeof(data), frame, &len); + return chrg_north_send(frame, len); +} + static rt_uint8_t chrg_sink_init_build_commands(struct chrg_switch_t *pSW, rt_uint16_t *regs, rt_uint16_t *vals) { diff --git a/apps/chrg/applications/utils/chrg_sink.h b/apps/chrg/applications/utils/chrg_sink.h index 9c3d409..426cd83 100644 --- a/apps/chrg/applications/utils/chrg_sink.h +++ b/apps/chrg/applications/utils/chrg_sink.h @@ -71,7 +71,15 @@ struct test #define SINK_CMD_GET_VOLTAGE 0x20 // 读取变电压板电压 #define SINK_CMD_RESET 0x01 // 复位Sink协议板 +#define SINK_CMD_SET_DPDM_CAL 0x32 // 写入D+/D-校准参数 +/* D+/D-校准系数:K为实际比例系数放大10000倍,B单位为0.01V。 */ +struct sink_dpdm_cal_t { + rt_uint16_t dz_k; + rt_int16_t dz_b; + rt_uint16_t df_k; + rt_int16_t df_b; +}; struct sink_vc_t { rt_uint8_t voltage; // 电压 0.01V @@ -215,7 +223,7 @@ enum { /* Sink电压稳定确认参数,供chrg_sink_volt_judge使用。 */ #define SINK_VOLT_5V_TARGET_MV 5000U #define SINK_VOLT_CONFIRM_NORMAL_COUNT 3U -#define SINK_VOLT_CONFIRM_5V_COUNT 12U +#define SINK_VOLT_CONFIRM_5V_COUNT 3U #define SINK_CURRENT_START_GRACE_MS 200U /* 主继电器闭合后的0V持续监控:由北向轮询线程每轮调用,掉电立即转掉电保护。 */ @@ -266,6 +274,7 @@ struct chrg_sink_t { rt_uint8_t change_cv_flag; rt_uint8_t change_source_flag; // 从sink切换到source标志位 rt_uint8_t work_mode; // 0=停止 1=工作 2=低电压 + struct sink_dpdm_cal_t dpdm_cal; // 上位机待写入Sink板的D+/D-校准参数 }; //纹波寄存器 @@ -408,6 +417,16 @@ extern int sink_set_cc_lvl (rt_uint8_t lvl); 其它说明: - *****************************************************************/ extern int sink_set_pd (rt_uint8_t pd, rt_uint8_t *buf); + +/***************************************************************** +函数名称: sink_set_dpdm_cal +函数描述: 向Sink协议板写入D+/D-校准参数 +输入参数: pCal:四个16位校准参数 +输出参数: - +返回说明: <0:发送失败 >0:发送长度 +其它说明: 发送0x32;K为×10000,B为0.01V有符号补码 +*****************************************************************/ +extern int sink_set_dpdm_cal(const struct sink_dpdm_cal_t *pCal); // ===================== 负载测试函数声明 ===================== extern void sink_test_short_set (struct chrg_switch_t *pSW, rt_uint8_t *pData, rt_uint8_t run_flag); extern void sink_test_ocp_set (struct chrg_switch_t *pSW, rt_uint8_t *pData, rt_uint8_t run_flag); diff --git a/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx b/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx index c263bf5..9fced9d 100644 Binary files a/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx and b/docs/QMP4810300-4多协议可编程双向电源通信协议V_1.2.xlsx differ diff --git a/docs/修改日志.md b/docs/修改日志.md index 08c6e10..2483f12 100644 --- a/docs/修改日志.md +++ b/docs/修改日志.md @@ -1,5 +1,15 @@ # 修改日志 +## V1.1.56 - 2026-10-09 + +### Sink板D+/D-校准参数写入 + +- 增加每通道四个16位D+/D-校准参数:D+K、D+B、D-K、D-B;K按10000倍传递,B为0.01V有符号值。 +- 上位机写入参数并触发原有 `PARAM_EFFECT` 后,405通过北向Sink板 `0x32` 指令写入参数。 +- 写入任务复用北向通道切换、事务号和回码校验;仅在通道空闲量测状态提交,完成后恢复普通轮询。 +- 本版本不包含 `0x31` 采样、`0x33` 读取、`0x34` 恢复和五点拟合。 +- 协议板版本寄存器 `0x0300` 更新为 `0x0148`。 + ## V1.1.55 - 2026-10-09 ### Sink协议切换复位开关